1 /***********************************************************************
2 LocalWaterTool - Tool class to locally add or remove water from an
3 augmented reality sandbox.
4 Copyright (c) 2012-2013 Oliver Kreylos
6 This file is part of the Augmented Reality Sandbox (SARndbox).
8 The Augmented Reality Sandbox is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of the
11 License, or (at your option) any later version.
13 The Augmented Reality Sandbox is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License along
19 with the Augmented Reality Sandbox; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 ***********************************************************************/
23 #include "LocalWaterTool.h"
25 #include <Misc/FunctionCalls.h>
27 #include <GL/Extensions/GLARBVertexProgram.h>
28 #include <GL/GLGeometryWrappers.h>
29 #include <GL/GLTransformationWrappers.h>
30 #include <Vrui/Vrui.h>
31 #include <Vrui/ToolManager.h>
32 #include <Vrui/DisplayState.h>
34 #include "WaterTable2.h"
37 /***************************************
38 Static elements of class LocalWaterTool:
39 ***************************************/
41 LocalWaterToolFactory
* LocalWaterTool::factory
= 0;
43 /*******************************
44 Methods of class LocalWaterTool:
45 *******************************/
47 LocalWaterToolFactory
* LocalWaterTool::initClass(Vrui::ToolManager
& toolManager
) {
48 /* Create the tool factory: */
49 factory
= new LocalWaterToolFactory("LocalWaterTool", "Manage Water Locally", 0, toolManager
);
51 /* Set up the tool class' input layout: */
52 factory
->setNumButtons(2);
53 factory
->setButtonFunction(0, "Rain");
54 factory
->setButtonFunction(1, "Dry");
56 /* Register and return the class: */
57 toolManager
.addClass(factory
, Vrui::ToolManager::defaultToolFactoryDestructor
);
61 LocalWaterTool::LocalWaterTool(const Vrui::ToolFactory
* factory
,
62 const Vrui::ToolInputAssignment
& inputAssignment
)
63 : Vrui::Tool(factory
, inputAssignment
),
68 LocalWaterTool::~LocalWaterTool(void) {
71 void LocalWaterTool::initialize(void) {
72 /* Register a render function with the water table: */
73 if(application
->waterTable
!= 0) {
74 addWaterFunction
= Misc::createFunctionCall(this, &LocalWaterTool::addWater
);
75 application
->waterTable
->addRenderFunction(addWaterFunction
);
79 void LocalWaterTool::deinitialize(void) {
80 /* Unregister the render function from the water table: */
81 if(application
->waterTable
!= 0)
82 application
->waterTable
->removeRenderFunction(addWaterFunction
);
83 delete addWaterFunction
;
87 const Vrui::ToolFactory
* LocalWaterTool::getFactory(void) const {
91 void LocalWaterTool::buttonCallback(int buttonSlotIndex
,
92 Vrui::InputDevice::ButtonCallbackData
* cbData
) {
93 GLfloat waterAmount
= application
->rainStrength
;
94 if(!cbData
->newButtonState
)
95 waterAmount
= -waterAmount
;
96 if(buttonSlotIndex
== 1)
97 waterAmount
= -waterAmount
;
98 adding
+= waterAmount
;
101 void LocalWaterTool::initContext(GLContextData
& contextData
) const {
102 /* Initialize the required OpenGL extensions: */
103 GLARBVertexProgram::initExtension();
106 void LocalWaterTool::glRenderActionTransparent(GLContextData
& contextData
) const {
107 glPushAttrib(GL_ENABLE_BIT
| GL_POLYGON_BIT
);
109 /* Go to navigational coordinates: */
111 glLoadMatrix(Vrui::getDisplayState(contextData
).modelviewNavigational
);
113 /* Get the current rain disk position and size in camera coordinates: */
114 Vrui::Point rainPos
= Vrui::getInverseNavigationTransformation().transform(getButtonDevicePosition(
116 Vrui::Scalar rainRadius
= Vrui::getPointPickDistance() * Vrui::Scalar(3);
118 /* Construct the rain cylinder: */
119 Vrui::Vector z
= application
->waterTable
->getBaseTransform().inverseTransform(Vrui::Vector(0, 0,
121 Vrui::Vector x
= Geometry::normal(z
);
122 Vrui::Vector y
= Geometry::cross(z
, x
);
126 /* Set the rain cylinder's material: */
127 GLfloat diffuseCol
[4] = {0.0f
, 0.0f
, 1.0f
, 0.333f
};
128 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, diffuseCol
);
130 /* Render the back faces of the rain cylinder: */
131 glCullFace(GL_FRONT
);
132 glBegin(GL_QUAD_STRIP
);
133 for(int i
= 0; i
<= 32; ++i
) {
134 Vrui::Scalar angle
= Vrui::Scalar(2) * Math::Constants
<Vrui::Scalar
>::pi
* Vrui::Scalar(
135 i
) / Vrui::Scalar(32);
136 glNormal(x
* Math::cos(angle
) + y
* Math::sin(angle
));
137 glVertex(rainPos
+ x
* (Math::cos(angle
)*rainRadius
) + y
* (Math::sin(angle
)*rainRadius
));
138 glVertex(rainPos
+ x
* (Math::cos(angle
)*rainRadius
) + y
* (Math::sin(
139 angle
)*rainRadius
) - z
* Vrui::Scalar(50));
143 /* Render the front faces of the rain cylinder: */
145 glBegin(GL_QUAD_STRIP
);
146 for(int i
= 0; i
<= 32; ++i
) {
147 Vrui::Scalar angle
= Vrui::Scalar(2) * Math::Constants
<Vrui::Scalar
>::pi
* Vrui::Scalar(
148 i
) / Vrui::Scalar(32);
149 glNormal(x
* Math::cos(angle
) + y
* Math::sin(angle
));
150 glVertex(rainPos
+ x
* (Math::cos(angle
)*rainRadius
) + y
* (Math::sin(angle
)*rainRadius
));
151 glVertex(rainPos
+ x
* (Math::cos(angle
)*rainRadius
) + y
* (Math::sin(
152 angle
)*rainRadius
) - z
* Vrui::Scalar(50));
157 for(int i
= 0; i
< 32; ++i
) {
158 Vrui::Scalar angle
= Vrui::Scalar(2) * Math::Constants
<Vrui::Scalar
>::pi
* Vrui::Scalar(
159 i
) / Vrui::Scalar(32);
160 glVertex(rainPos
+ x
* (Math::cos(angle
)*rainRadius
) + y
* (Math::sin(angle
)*rainRadius
));
168 void LocalWaterTool::addWater(GLContextData
& contextData
) const {
170 glPushAttrib(GL_ENABLE_BIT
);
171 glDisable(GL_CULL_FACE
);
173 /* Get the current rain disk position and size in camera coordinates: */
174 Vrui::Point rainPos
= Vrui::getInverseNavigationTransformation().transform(getButtonDevicePosition(
176 Vrui::Scalar rainRadius
= Vrui::getPointPickDistance() * Vrui::Scalar(3);
178 /* Render the rain disk: */
179 Vrui::Vector z
= application
->waterTable
->getBaseTransform().inverseTransform(Vrui::Vector(0, 0,
181 Vrui::Vector x
= Geometry::normal(z
);
182 Vrui::Vector y
= Geometry::cross(z
, x
);
183 x
*= rainRadius
/ Geometry::mag(x
);
184 y
*= rainRadius
/ Geometry::mag(y
);
186 glVertexAttrib1fARB(1, adding
/ application
->waterSpeed
);
188 for(int i
= 0; i
< 32; ++i
) {
189 Vrui::Scalar angle
= Vrui::Scalar(2) * Math::Constants
<Vrui::Scalar
>::pi
* Vrui::Scalar(
190 i
) / Vrui::Scalar(32);
191 glVertex(rainPos
+ x
* Math::cos(angle
) + y
* Math::sin(angle
));