2002-07-17 04:07:32 +08:00
|
|
|
//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield
|
2001-10-04 23:12:57 +08:00
|
|
|
//Distributed under the terms of the GNU Library General Public License (LGPL)
|
|
|
|
//as published by the Free Software Foundation.
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
#ifndef OSGUTIL_SCENEVIEW
|
|
|
|
#define OSGUTIL_SCENEVIEW 1
|
|
|
|
|
|
|
|
#include <osg/Node>
|
2001-09-20 05:08:56 +08:00
|
|
|
#include <osg/StateSet>
|
2001-01-11 00:32:10 +08:00
|
|
|
#include <osg/Light>
|
|
|
|
#include <osg/Camera>
|
2001-09-22 10:42:08 +08:00
|
|
|
#include <osg/FrameStamp>
|
2001-12-22 06:48:19 +08:00
|
|
|
#include <osg/DisplaySettings>
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2002-04-01 00:40:44 +08:00
|
|
|
|
2002-04-11 16:24:55 +08:00
|
|
|
#include <osgUtil/CullVisitor>
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
namespace osgUtil {
|
|
|
|
|
|
|
|
/**
|
2001-09-28 20:36:40 +08:00
|
|
|
* SceneView is literally a view of a scene, encapsulating the
|
2001-01-11 00:32:10 +08:00
|
|
|
* camera, global state, lights and the scene itself. Provides
|
|
|
|
* methods for setting up the view and rendering it.
|
|
|
|
*/
|
|
|
|
class OSGUTIL_EXPORT SceneView : public osg::Referenced
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
2001-09-28 20:36:40 +08:00
|
|
|
/** Construct a default scene view.*/
|
2001-12-22 06:48:19 +08:00
|
|
|
SceneView(osg::DisplaySettings* ds=NULL);
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2001-09-22 10:42:08 +08:00
|
|
|
/** Set scene view to use default global state, light, camera
|
|
|
|
* and render visitor.
|
|
|
|
*/
|
|
|
|
void setDefaults();
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
/** Set the data which to view. The data will typically be
|
|
|
|
* an osg::Scene but can be any osg::Node type.
|
|
|
|
*/
|
2002-07-21 09:29:11 +08:00
|
|
|
void setSceneData(osg::Node* node) { _sceneData = node; }
|
2001-01-11 00:32:10 +08:00
|
|
|
/** Get the scene data which to view. The data will typically be
|
|
|
|
* an osg::Scene but can be any osg::Node type.
|
|
|
|
*/
|
|
|
|
osg::Node* getSceneData() { return _sceneData.get(); }
|
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
/** Get the const scene data which to view. The data will typically be
|
|
|
|
* an osg::Scene but can be any osg::Node type.
|
|
|
|
*/
|
|
|
|
const osg::Node* getSceneData() const { return _sceneData.get(); }
|
|
|
|
|
2001-09-22 10:42:08 +08:00
|
|
|
/** Set the viewport of the scene view to use specfied osg::Viewport. */
|
|
|
|
void setViewport(osg::Viewport* viewport)
|
|
|
|
{
|
|
|
|
if (viewport) _viewport = viewport;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// ensure that _viewport is always valid.
|
2002-07-21 07:54:55 +08:00
|
|
|
_viewport = osgNew osg::Viewport;
|
2001-09-22 10:42:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Set the viewport of the scene view to specified dimensions. */
|
2001-01-11 00:32:10 +08:00
|
|
|
void setViewport(int x,int y,int width,int height)
|
|
|
|
{
|
2001-09-22 10:42:08 +08:00
|
|
|
_viewport->setViewport(x,y,width,height);
|
2001-01-11 00:32:10 +08:00
|
|
|
}
|
|
|
|
|
2001-09-22 10:42:08 +08:00
|
|
|
|
|
|
|
/** Get the const viewport. */
|
|
|
|
const osg::Viewport* getViewport() const { return _viewport.get(); }
|
|
|
|
|
|
|
|
/** Get the viewport. */
|
|
|
|
osg::Viewport* getViewport() { return _viewport.get(); }
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
/** Get the viewport of the scene view. */
|
|
|
|
void getViewport(int& x,int& y,int& width,int& height)
|
|
|
|
{
|
2001-09-22 10:42:08 +08:00
|
|
|
_viewport->getViewport(x,y,width,height);
|
2001-01-11 00:32:10 +08:00
|
|
|
}
|
|
|
|
|
2001-12-22 06:48:19 +08:00
|
|
|
/** Set the DisplaySettings. */
|
|
|
|
inline void setDisplaySettings(osg::DisplaySettings* vs) { _displaySettings = vs; }
|
2001-12-19 08:38:23 +08:00
|
|
|
|
2002-03-28 00:31:25 +08:00
|
|
|
/** Get the const DisplaySettings */
|
2001-12-22 06:48:19 +08:00
|
|
|
inline const osg::DisplaySettings* getDisplaySettings() const { return _displaySettings.get(); }
|
2002-03-28 00:31:25 +08:00
|
|
|
|
|
|
|
/** Get the DisplaySettings */
|
|
|
|
inline osg::DisplaySettings* getDisplaySettings() { return _displaySettings.get(); }
|
2001-09-22 10:42:08 +08:00
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
/** Set the background color used in glClearColor().
|
|
|
|
Defaults to an off blue color.*/
|
|
|
|
void setBackgroundColor(const osg::Vec4& color) { _backgroundColor=color; }
|
|
|
|
/** Get the background color.*/
|
|
|
|
const osg::Vec4& getBackgroundColor() const { return _backgroundColor; }
|
|
|
|
|
2001-11-14 22:09:07 +08:00
|
|
|
void setGlobalStateSet(osg::StateSet* state) { _globalState = state; }
|
|
|
|
osg::StateSet* getGlobalStateSet() { return _globalState.get(); }
|
|
|
|
const osg::StateSet* getGlobalStateSet() const { return _globalState.get(); }
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
enum LightingMode {
|
|
|
|
HEADLIGHT, // default
|
|
|
|
SKY_LIGHT,
|
|
|
|
NO_SCENEVIEW_LIGHT
|
|
|
|
};
|
|
|
|
|
|
|
|
void setLightingMode(LightingMode mode) { _lightingMode=mode; }
|
|
|
|
LightingMode getLightingMode() const { return _lightingMode; }
|
|
|
|
|
|
|
|
void setLight(osg::Light* light) { _light = light; }
|
2001-09-20 05:08:56 +08:00
|
|
|
osg::Light* getLight() { return _light.get(); }
|
|
|
|
const osg::Light* getLight() const { return _light.get(); }
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
void setState(osg::State* state) { _state = state; }
|
|
|
|
osg::State* getState() { return _state.get(); }
|
|
|
|
const osg::State* getState() const { return _state.get(); }
|
2001-12-03 06:20:46 +08:00
|
|
|
|
2002-04-13 02:06:13 +08:00
|
|
|
|
|
|
|
/** set an osg::Camera for the scene view to use for setting projection and modelview matrices internaly.
|
|
|
|
* However, the projection matrix from the camera will be overriden by a projection matrix which is set explicitly
|
|
|
|
* via setProjectionMatrix(..), see below.
|
|
|
|
* Also, the model matrix from the camera will be overriden by a modelview matrix which is set explicitly
|
|
|
|
* via setModelViewMatrix(..), see below.*/
|
2001-12-03 06:20:46 +08:00
|
|
|
void setCamera(osg::Camera* camera) { _camera = camera; }
|
|
|
|
osg::Camera* getCamera() { return _camera.get(); }
|
|
|
|
const osg::Camera* getCamera() const { return _camera.get(); }
|
|
|
|
|
2002-04-13 19:08:04 +08:00
|
|
|
/** set a projection matrix. Note, this will override a camera's projection matrix if it is not NULL.*/
|
2002-04-10 05:46:34 +08:00
|
|
|
void setProjectionMatrix(osg::Matrix* matrix) { _projectionMatrix = matrix; }
|
|
|
|
osg::Matrix* getProjectionMatrix() { return _projectionMatrix.get(); }
|
|
|
|
const osg::Matrix* getProjectionMatrix() const { return _projectionMatrix.get(); }
|
|
|
|
|
2002-04-13 19:08:04 +08:00
|
|
|
/** set a modelview matrix. Note, this will override a camera's modelview matrix if it is not NULL.*/
|
2002-04-10 05:46:34 +08:00
|
|
|
void setModelViewMatrix(osg::Matrix* matrix) { _modelviewMatrix = matrix; }
|
|
|
|
osg::Matrix* getModelViewMatrix() { return _modelviewMatrix.get(); }
|
|
|
|
const osg::Matrix* getModelViewMatrix() const { return _modelviewMatrix.get(); }
|
2001-12-19 08:38:23 +08:00
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
|
2001-10-21 04:26:36 +08:00
|
|
|
void setInitVisitor(osg::NodeVisitor* av) { _initVisitor = av; }
|
|
|
|
osg::NodeVisitor* getInitVisitor() { return _initVisitor.get(); }
|
|
|
|
const osg::NodeVisitor* getInitVisitor() const { return _initVisitor.get(); }
|
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
void setAppVisitor(osg::NodeVisitor* av) { _appVisitor = av; }
|
|
|
|
osg::NodeVisitor* getAppVisitor() { return _appVisitor.get(); }
|
|
|
|
const osg::NodeVisitor* getAppVisitor() const { return _appVisitor.get(); }
|
|
|
|
|
|
|
|
void setCullVisitor(osgUtil::CullVisitor* cv) { _cullVisitor = cv; }
|
|
|
|
osgUtil::CullVisitor* getCullVisitor() { return _cullVisitor.get(); }
|
|
|
|
const osgUtil::CullVisitor* getCullVisitor() const { return _cullVisitor.get(); }
|
|
|
|
|
|
|
|
void setRenderGraph(osgUtil::RenderGraph* rg) { _rendergraph = rg; }
|
|
|
|
osgUtil::RenderGraph* getRenderGraph() { return _rendergraph.get(); }
|
|
|
|
const osgUtil::RenderGraph* getRenderGraph() const { return _rendergraph.get(); }
|
|
|
|
|
|
|
|
void setRenderStage(osgUtil::RenderStage* rs) { _renderStage = rs; }
|
|
|
|
osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); }
|
|
|
|
const osgUtil::RenderStage* getRenderStage() const { return _renderStage.get(); }
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2002-03-04 06:31:46 +08:00
|
|
|
|
|
|
|
void setCullMask(const osg::Node::NodeMask nm) { _cullMask = nm; }
|
|
|
|
const osg::Node::NodeMask getCullMask() const { return _cullMask; }
|
|
|
|
|
|
|
|
void setCullMaskLeft(const osg::Node::NodeMask nm) { _cullMaskLeft = nm; }
|
|
|
|
const osg::Node::NodeMask getCullMaskLeft() const { return _cullMaskLeft; }
|
|
|
|
|
|
|
|
void setCullMaskRight(const osg::Node::NodeMask nm) { _cullMaskRight = nm; }
|
|
|
|
const osg::Node::NodeMask getCullMaskRight() const { return _cullMaskRight; }
|
|
|
|
|
2002-07-03 03:53:18 +08:00
|
|
|
/** Set the LOD bias for the CullVisitor to use.*/
|
|
|
|
void setLODBias(float bias) { _LODBias = bias; }
|
|
|
|
|
|
|
|
/** Get the LOD bias.*/
|
|
|
|
float getLODBias() const { return _LODBias; }
|
|
|
|
|
|
|
|
/** Set the Small Feature Culling Pixel Size.*/
|
|
|
|
void setSmallFeatureCullingPixelSize(float value) { _smallFeatureCullingPixelSize=value; }
|
|
|
|
|
|
|
|
/** Get the Small Feature Culling Pixel Size.*/
|
|
|
|
float getSmallFeatureCullingPixelSize() const { return _smallFeatureCullingPixelSize; }
|
|
|
|
|
|
|
|
/** Set the culling mode for the CullVisitor to use.*/
|
|
|
|
void setCullingMode(osg::CullStack::CullingMode mode) { _cullingMode = mode; }
|
|
|
|
|
|
|
|
/** Returns the current CullingMode.*/
|
|
|
|
osg::CullStack::CullingMode getCullingMode() const { return _cullingMode; }
|
|
|
|
|
|
|
|
/** Set the ComputeNearFarMode for the CullVisitor to use.*/
|
|
|
|
void setComputeNearFarMode(CullVisitor::ComputeNearFarMode cnfm) { _computeNearFar=cnfm; }
|
|
|
|
|
|
|
|
/** Get the ComputeNearFarMode.*/
|
|
|
|
CullVisitor::ComputeNearFarMode getComputeNearFarMode() const { return _computeNearFar;}
|
|
|
|
|
2002-09-04 18:49:17 +08:00
|
|
|
/** FusionDistanceMode is used only when working in stereo.*/
|
|
|
|
enum FusionDistanceMode
|
|
|
|
{
|
|
|
|
/** Use fusion distance from the attached camera if one exist.*/
|
|
|
|
USE_CAMERA_FUSION_DISTANCE,
|
|
|
|
/** Use fusion distance from the value set on the SceneView.*/
|
|
|
|
USE_FUSION_DISTANCE_VALUE,
|
|
|
|
/** Compute the fusion distance by multiplying the screen distance by the fusion distance value.*/
|
|
|
|
PROPORTIONAL_TO_SCREEN_DISTANCE
|
|
|
|
};
|
|
|
|
|
|
|
|
/** Set the FusionDistanceMode and Value. Note, is used only when working in stereo.*/
|
2002-09-12 22:29:59 +08:00
|
|
|
void setFusionDistance(FusionDistanceMode mode,float value=1.0f)
|
|
|
|
{
|
|
|
|
_fusionDistanceMode = mode;
|
|
|
|
_fusionDistanceValue = value;
|
|
|
|
}
|
2002-09-04 18:49:17 +08:00
|
|
|
|
|
|
|
/** Get the FusionDistanceMode.*/
|
|
|
|
FusionDistanceMode getFusionDistanceMode() const { return _fusionDistanceMode; }
|
|
|
|
|
|
|
|
/** Get the FusionDistanceValue. Note, only used for USE_FUSION_DISTANCE_VALUE & PROPORTIONAL_TO_SCREEN_DISTANCE modes.*/
|
|
|
|
float getFusionDistanceValue() const { return _fusionDistanceValue; }
|
2002-03-04 06:31:46 +08:00
|
|
|
|
2001-09-20 05:08:56 +08:00
|
|
|
|
|
|
|
/** set whether the draw method should call renderer->prioritizeTexture.*/
|
|
|
|
void setPrioritizeTextures(bool pt) { _prioritizeTextures = pt; }
|
|
|
|
|
|
|
|
/** get whether the draw method should call renderer->prioritizeTexture.*/
|
|
|
|
bool getPrioritizeTextures() const { return _prioritizeTextures; }
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
/** Calculate, via glUnProject, the object coordinates of a window point.
|
|
|
|
Note, current implementation requires that SceneView::draw() has been previously called
|
|
|
|
for projectWindowIntoObject to produce valid values. Consistent with OpenGL
|
|
|
|
windows coordinates are calculated relative to the bottom left of the window.
|
|
|
|
Returns true on successful projection.
|
|
|
|
*/
|
|
|
|
bool projectWindowIntoObject(const osg::Vec3& window,osg::Vec3& object) const;
|
|
|
|
|
|
|
|
/** Calculate, via glUnProject, the object coordinates of a window x,y
|
|
|
|
when projected onto the near and far planes.
|
|
|
|
Note, current implementation requires that SceneView::draw() has been previously called
|
|
|
|
for projectWindowIntoObject to produce valid values. Consistent with OpenGL
|
|
|
|
windows coordinates are calculated relative to the bottom left of the window.
|
|
|
|
Returns true on successful projection.
|
|
|
|
*/
|
|
|
|
bool projectWindowXYIntoObject(int x,int y,osg::Vec3& near_point,osg::Vec3& far_point) const;
|
|
|
|
|
|
|
|
/** Calculate, via glProject, the object coordinates of a window.
|
|
|
|
Note, current implementation requires that SceneView::draw() has been previously called
|
|
|
|
for projectWindowIntoObject to produce valid values. Consistent with OpenGL
|
|
|
|
windows coordinates are calculated relative to the bottom left of the window,
|
|
|
|
whereas as window API's normally have the top left as the origin,
|
|
|
|
so you may need to pass in (mouseX,window_height-mouseY,...).
|
|
|
|
Returns true on successful projection.
|
|
|
|
*/
|
|
|
|
bool projectObjectIntoWindow(const osg::Vec3& object,osg::Vec3& window) const;
|
|
|
|
|
|
|
|
|
2001-09-22 10:42:08 +08:00
|
|
|
/** Set the frame stamp for the current frame.*/
|
|
|
|
inline void setFrameStamp(osg::FrameStamp* fs) { _frameStamp = fs; }
|
|
|
|
|
|
|
|
/** Set the frame stamp for the current frame.*/
|
|
|
|
inline const osg::FrameStamp* getFrameStamp() const { return _frameStamp.get(); }
|
|
|
|
|
|
|
|
|
2001-10-21 04:26:36 +08:00
|
|
|
/** Do init traversal of attached scene graph using Init NodeVisitor.
|
|
|
|
* The init traversal is called once for each SceneView, and should
|
|
|
|
* be used to compile display list, texture objects intialize data
|
|
|
|
* not otherwise intializaed during scene graph loading. Note, is
|
|
|
|
* called automatically by app&cull if it hasn't already been called
|
|
|
|
* elsewhere. Also init() should only ever be called within a valid
|
|
|
|
* graphics context.*/
|
|
|
|
virtual void init();
|
2001-09-22 10:42:08 +08:00
|
|
|
|
2001-10-21 04:26:36 +08:00
|
|
|
/** Do app traversal of attached scene graph using App NodeVisitor.*/
|
2001-09-20 05:08:56 +08:00
|
|
|
virtual void app();
|
|
|
|
|
2001-10-21 04:26:36 +08:00
|
|
|
/** Do cull traversal of attached scene graph using Cull NodeVisitor.*/
|
2001-01-11 00:32:10 +08:00
|
|
|
virtual void cull();
|
2001-09-20 05:08:56 +08:00
|
|
|
|
2001-10-21 04:26:36 +08:00
|
|
|
/** Do draw traversal of draw bins generated by cull traversal.*/
|
2001-01-11 00:32:10 +08:00
|
|
|
virtual void draw();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
virtual ~SceneView();
|
|
|
|
|
2002-02-14 21:26:37 +08:00
|
|
|
/** Do cull traversal of attached scene graph using Cull NodeVisitor.*/
|
2002-04-13 02:06:13 +08:00
|
|
|
virtual void cullStage(osg::Matrix* projection,osg::Matrix* modelview,osgUtil::CullVisitor* cullVisitor, osgUtil::RenderGraph* rendergraph, osgUtil::RenderStage* renderStage);
|
2002-02-14 21:26:37 +08:00
|
|
|
|
2002-04-16 19:41:32 +08:00
|
|
|
const osg::Matrix computeMVPW() const;
|
|
|
|
|
2002-04-16 23:31:46 +08:00
|
|
|
void clearArea(int x,int y,int width,int height,const osg::Vec4& color);
|
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
osg::ref_ptr<osg::Node> _sceneData;
|
2001-09-20 05:08:56 +08:00
|
|
|
osg::ref_ptr<osg::StateSet> _globalState;
|
2001-01-11 00:32:10 +08:00
|
|
|
osg::ref_ptr<osg::Light> _light;
|
|
|
|
osg::ref_ptr<osg::Camera> _camera;
|
2002-04-10 05:46:34 +08:00
|
|
|
osg::ref_ptr<osg::Matrix> _projectionMatrix;
|
|
|
|
osg::ref_ptr<osg::Matrix> _modelviewMatrix;
|
2001-12-22 06:48:19 +08:00
|
|
|
osg::ref_ptr<osg::DisplaySettings> _displaySettings;
|
2001-09-20 05:08:56 +08:00
|
|
|
osg::ref_ptr<osg::State> _state;
|
|
|
|
|
2001-10-21 04:26:36 +08:00
|
|
|
bool _initCalled;
|
|
|
|
osg::ref_ptr<osg::NodeVisitor> _initVisitor;
|
2001-09-20 05:08:56 +08:00
|
|
|
osg::ref_ptr<osg::NodeVisitor> _appVisitor;
|
2002-03-04 06:31:46 +08:00
|
|
|
osg::Node::NodeMask _cullMask;
|
2001-09-20 05:08:56 +08:00
|
|
|
osg::ref_ptr<osgUtil::CullVisitor> _cullVisitor;
|
|
|
|
osg::ref_ptr<osgUtil::RenderGraph> _rendergraph;
|
|
|
|
osg::ref_ptr<osgUtil::RenderStage> _renderStage;
|
2002-02-14 21:26:37 +08:00
|
|
|
|
2002-03-04 06:31:46 +08:00
|
|
|
osg::Node::NodeMask _cullMaskLeft;
|
2002-02-19 07:01:09 +08:00
|
|
|
osg::ref_ptr<osgUtil::CullVisitor> _cullVisitorLeft;
|
|
|
|
osg::ref_ptr<osgUtil::RenderGraph> _rendergraphLeft;
|
2002-02-14 21:26:37 +08:00
|
|
|
osg::ref_ptr<osgUtil::RenderStage> _renderStageLeft;
|
2002-02-19 07:01:09 +08:00
|
|
|
|
2002-03-04 06:31:46 +08:00
|
|
|
osg::Node::NodeMask _cullMaskRight;
|
2002-02-19 07:01:09 +08:00
|
|
|
osg::ref_ptr<osgUtil::CullVisitor> _cullVisitorRight;
|
|
|
|
osg::ref_ptr<osgUtil::RenderGraph> _rendergraphRight;
|
2002-02-14 21:26:37 +08:00
|
|
|
osg::ref_ptr<osgUtil::RenderStage> _renderStageRight;
|
|
|
|
|
2002-09-04 18:49:17 +08:00
|
|
|
osg::ref_ptr<osg::FrameStamp> _frameStamp;
|
|
|
|
|
|
|
|
osg::Vec4 _backgroundColor;
|
2001-09-20 05:08:56 +08:00
|
|
|
|
2002-09-04 18:49:17 +08:00
|
|
|
CullVisitor::ComputeNearFarMode _computeNearFar;
|
|
|
|
osg::CullStack::CullingMode _cullingMode;
|
|
|
|
float _LODBias;
|
|
|
|
float _smallFeatureCullingPixelSize;
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2002-09-04 18:49:17 +08:00
|
|
|
FusionDistanceMode _fusionDistanceMode;
|
|
|
|
float _fusionDistanceValue;
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2002-09-04 18:49:17 +08:00
|
|
|
osg::ref_ptr<osg::Viewport> _viewport;
|
2001-01-11 00:32:10 +08:00
|
|
|
|
2002-09-04 18:49:17 +08:00
|
|
|
LightingMode _lightingMode;
|
2001-09-20 05:08:56 +08:00
|
|
|
|
2002-09-04 18:49:17 +08:00
|
|
|
bool _prioritizeTextures;
|
2001-09-20 05:08:56 +08:00
|
|
|
|
2001-01-11 00:32:10 +08:00
|
|
|
};
|
|
|
|
|
2002-02-03 20:33:41 +08:00
|
|
|
}
|
2001-01-11 00:32:10 +08:00
|
|
|
|
|
|
|
#endif
|
|
|
|
|