root/OpenSceneGraph/trunk/src/osgPlugins/vnc/ReaderWriterVNC.cpp @ 13041

Revision 13041, 12.6 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1999-2008 Robert Osfield
2 *
3 * This software is open source and may be redistributed and/or modified under
4 * the terms of the GNU General Public License (GPL) version 2.0.
5 * The full license is in LICENSE.txt file included with this distribution,.
6 *
7 * This software is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 * include LICENSE.txt for more details.
11*/
12
13#include <osg/Timer>
14
15#include <osgDB/ReaderWriter>
16#include <osgDB/FileNameUtils>
17#include <osgDB/Registry>
18
19#include <osgWidget/VncClient>
20
21extern "C" {
22#include <rfb/rfbclient.h>
23}
24
25class LibVncImage : public osgWidget::VncImage
26{
27    public:
28
29        LibVncImage();
30
31        bool connect(const std::string& hostname);
32
33        void close();
34
35        virtual bool sendPointerEvent(int x, int y, int buttonMask);
36
37        double getTimeOfLastUpdate() const { return _timeOfLastUpdate; }
38        double getTimeOfLastRender() const { return _timeOfLastRender; }
39
40        double time() const { return osg::Timer::instance()->time_s(); }
41
42        virtual bool sendKeyEvent(int key, bool keyDown);
43
44        virtual void setFrameLastRendered(const osg::FrameStamp* frameStamp);
45
46        void updated();
47
48        static rfbBool resizeImage(rfbClient* client);
49
50        static void updateImage(rfbClient* client,int x,int y,int w,int h);
51
52        static void passwordCheck(rfbClient* client,const char* encryptedPassWord,int len);
53        static char* getPassword(rfbClient* client);
54
55        std::string                 _optionString;
56        std::string                 _username;
57        std::string                 _password;
58
59        double                      _timeOfLastUpdate;
60        double                      _timeOfLastRender;
61
62        bool                        _active;
63        osg::ref_ptr<osg::RefBlock> _inactiveBlock;
64
65    protected:
66
67        virtual ~LibVncImage();
68
69        class RfbThread : public osg::Referenced, public OpenThreads::Thread
70        {
71        public:
72
73            RfbThread(rfbClient* client, LibVncImage* image):
74                _client(client),
75                _image(image),
76                _done(false) {}
77
78            virtual ~RfbThread()
79            {
80                _done = true;
81                while(isRunning())
82                {
83                    OpenThreads::Thread::YieldCurrentThread();
84                }
85            }
86
87            virtual void run()
88            {
89                do
90                {
91                    if (_image->_active)
92                    {
93                        int i=WaitForMessage(_client,5000);
94                        if(i<0)
95                            return;
96
97                        if(i)
98                        {
99                            OSG_INFO<<"VNC Handling "<<i<<" messages"<<std::endl;
100
101                            if(!HandleRFBServerMessage(_client))
102                            return;
103
104                            _image->updated();
105                        }
106                    }
107                    else
108                    {
109                        _image->_inactiveBlock->block();
110                    }
111
112
113                    double deltaTime = _image->getTimeOfLastRender() - _image->getTimeOfLastUpdate();
114                    if (deltaTime<-0.01)
115                    {
116                        //OSG_NOTICE<<"Inactive"<<std::endl;
117                        //_image->_active = false;
118                    }
119                    else
120                    {
121                        _image->_active = true;
122                    }
123
124                } while (!_done && !testCancel());
125            }
126
127            rfbClient*                      _client;
128            osg::observer_ptr<LibVncImage>  _image;
129            bool                            _done;
130
131        };
132
133    public:
134
135        rfbClient* _client;
136
137        osg::ref_ptr<RfbThread>     _rfbThread;
138
139};
140
141LibVncImage::LibVncImage():
142    _client(0)
143{
144    // setPixelBufferObject(new osg::PixelBufferObject(this);
145
146    _inactiveBlock = new osg::RefBlock;
147}
148
149LibVncImage::~LibVncImage()
150{
151    close();
152}
153
154static rfbBool rfbInitConnection(rfbClient* client)
155{
156  /* Unless we accepted an incoming connection, make a TCP connection to the
157     given VNC server */
158
159  if (!client->listenSpecified) {
160    if (!client->serverHost || !ConnectToRFBServer(client,client->serverHost,client->serverPort))
161      return FALSE;
162  }
163
164  /* Initialise the VNC connection, including reading the password */
165
166  if (!InitialiseRFBConnection(client))
167    return FALSE;
168
169  if (!SetFormatAndEncodings(client))
170    return FALSE;
171
172  client->width=client->si.framebufferWidth;
173  client->height=client->si.framebufferHeight;
174  client->MallocFrameBuffer(client);
175
176  if (client->updateRect.x < 0) {
177    client->updateRect.x = client->updateRect.y = 0;
178    client->updateRect.w = client->width;
179    client->updateRect.h = client->height;
180  }
181
182  if (client->appData.scaleSetting>1)
183  {
184      if (!SendScaleSetting(client, client->appData.scaleSetting))
185          return FALSE;
186      if (!SendFramebufferUpdateRequest(client,
187                  client->updateRect.x / client->appData.scaleSetting,
188                  client->updateRect.y / client->appData.scaleSetting,
189                  client->updateRect.w / client->appData.scaleSetting,
190                  client->updateRect.h / client->appData.scaleSetting,
191                  FALSE))
192          return FALSE;
193  }
194  else
195  {
196      if (!SendFramebufferUpdateRequest(client,
197                  client->updateRect.x, client->updateRect.y,
198                  client->updateRect.w, client->updateRect.h,
199                  FALSE))
200      return FALSE;
201  }
202
203  return TRUE;
204}
205
206void LibVncImage::passwordCheck(rfbClient* client,const char* encryptedPassWord,int len)
207{
208    OSG_NOTICE<<"LibVncImage::passwordCheck"<<std::endl;
209}
210
211char* LibVncImage::getPassword(rfbClient* client)
212{
213    LibVncImage* image = (LibVncImage*)(rfbClientGetClientData(client, 0));
214    OSG_NOTICE<<"LibVncImage::getPassword "<<image->_password<<std::endl;
215    return strdup(image->_password.c_str());
216}
217
218
219bool LibVncImage::connect(const std::string& hostname)
220{
221    if (hostname.empty()) return false;
222
223    if (_client) close();
224
225    _client = rfbGetClient(8,3,4);
226    _client->canHandleNewFBSize = TRUE;
227    _client->MallocFrameBuffer = resizeImage;
228    _client->GotFrameBufferUpdate = updateImage;
229    _client->HandleKeyboardLedState = 0;
230    _client->HandleTextChat = 0;
231
232    // provide the password if we have one assigned
233    if (!_password.empty())  _client->GetPassword = getPassword;
234
235    rfbClientSetClientData(_client, 0, this);
236
237    _client->serverHost = strdup(hostname.c_str());
238
239    // _client->serverPort = ;
240    // _client->appData.qualityLevel = ;
241    // _client->appData.encodings = ;
242    // _client->appData.compressLevel = ;
243    // _client->appData.scaleSetting = ;
244
245    if(rfbInitConnection(_client))
246    {
247        _rfbThread = new RfbThread(_client, this);
248        _rfbThread->startThread();
249
250        return true;
251    }
252    else
253    {
254        close();
255
256        return false;
257    }
258}
259
260
261void LibVncImage::close()
262{
263    if (_rfbThread.valid())
264    {
265        _inactiveBlock->release();
266
267        // stop the client thread
268        _rfbThread = 0;
269    }
270
271    if (_client)
272    {
273        // close the client
274        rfbClientCleanup(_client);
275        _client = 0;
276    }
277}
278
279
280rfbBool LibVncImage::resizeImage(rfbClient* client)
281{
282    LibVncImage* image = (LibVncImage*)(rfbClientGetClientData(client, 0));
283
284    int width = client->width;
285    int height = client->height;
286    int depth = client->format.bitsPerPixel;
287
288    OSG_NOTICE<<"resize "<<width<<", "<<height<<", "<<depth<<" image = "<<image<<std::endl;
289    PrintPixelFormat(&(client->format));
290
291    bool swap = client->format.redShift!=0;
292
293    if (!image->_optionString.empty())
294    {
295        if (image->_optionString.find("swap")!=std::string::npos || image->_optionString.find("swop")!=std::string::npos) swap = true;
296    }
297
298    GLenum gl_pixelFormat = swap ? GL_BGRA : GL_RGBA;
299
300    if (!image->_optionString.empty())
301    {
302        if (image->_optionString.find("RGB")!=std::string::npos) gl_pixelFormat = GL_RGBA;
303        if (image->_optionString.find("RGBA")!=std::string::npos) gl_pixelFormat = GL_RGBA;
304        if (image->_optionString.find("BGR")!=std::string::npos) gl_pixelFormat = GL_BGRA;
305        if (image->_optionString.find("BGRA")!=std::string::npos) gl_pixelFormat = GL_BGRA;
306    }
307
308    image->allocateImage(width, height, 1, gl_pixelFormat, GL_UNSIGNED_BYTE);
309    image->setInternalTextureFormat(GL_RGBA);
310
311
312
313    client->frameBuffer= (uint8_t*)(image->data());
314
315    return TRUE;
316}
317
318void LibVncImage::updateImage(rfbClient* client,int x,int y,int w,int h)
319{
320    osg::Image* image = (osg::Image*)(rfbClientGetClientData(client, 0));
321    image->dirty();
322}
323
324bool LibVncImage::sendPointerEvent(int x, int y, int buttonMask)
325{
326    if (_client)
327    {
328        SendPointerEvent(_client ,x, y, buttonMask);
329        return true;
330    }
331    return false;
332}
333
334bool LibVncImage::sendKeyEvent(int key, bool keyDown)
335{
336    if (_client)
337    {
338        SendKeyEvent(_client, key, keyDown ? TRUE : FALSE);
339        return true;
340    }
341    return false;
342}
343
344
345void LibVncImage::setFrameLastRendered(const osg::FrameStamp*)
346{
347    _timeOfLastRender = time();
348
349    if (!_active) _inactiveBlock->release();
350    _active = true;
351}
352
353void LibVncImage::updated()
354{
355    _timeOfLastUpdate = time();
356}
357
358class ReaderWriterVNC : public osgDB::ReaderWriter
359{
360    public:
361
362        ReaderWriterVNC()
363        {
364            supportsExtension("vnc","VNC plugin");
365
366            supportsOption("swap","Swaps the pixel format order, exchanging the red and blue channels.");
367            supportsOption("swop","American spelling, same effect as swap.");
368            supportsOption("RGB","Use RGBA pixel format for the vnc image");
369            supportsOption("RGBA","Use RGBA pixel format for the vnc image");
370            supportsOption("BGR","Use BGRA pixel format for the vnc image");
371            supportsOption("BGRA","Use BGRA pixel format for the vnc image");
372        }
373
374        virtual const char* className() const { return "VNC plugin"; }
375
376        virtual osgDB::ReaderWriter::ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options) const
377        {
378            return readImage(file,options);
379        }
380
381        virtual osgDB::ReaderWriter::ReadResult readImage(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
382        {
383            if (!osgDB::equalCaseInsensitive(osgDB::getFileExtension(fileName),"vnc"))
384            {
385                return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
386            }
387
388            std::string hostname = osgDB::getNameLessExtension(fileName);
389
390            OSG_NOTICE<<"Hostname = "<<hostname<<std::endl;
391
392            osg::ref_ptr<LibVncImage> image = new LibVncImage;
393            image->setDataVariance(osg::Object::DYNAMIC);
394            image->setOrigin(osg::Image::TOP_LEFT);
395
396            const osgDB::AuthenticationMap* authenticationMap = (options && options->getAuthenticationMap()) ?
397                    options->getAuthenticationMap() :
398                    osgDB::Registry::instance()->getAuthenticationMap();
399
400            const osgDB::AuthenticationDetails* details = authenticationMap ?
401                authenticationMap->getAuthenticationDetails(hostname) :
402                0;
403
404            // configure authentication if required.
405            if (details)
406            {
407                OSG_NOTICE<<"Passing in password = "<<details->password<<std::endl;
408
409                image->_username = details->username;
410                image->_password = details->password;
411            }
412
413            if (options && !options->getOptionString().empty())
414            {
415                image->_optionString = options->getOptionString();
416            }
417
418            if (!image->connect(hostname))
419            {
420                return "Could not connect to "+hostname;
421            }
422
423            return image.get();
424        }
425
426        virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
427        {
428            osgDB::ReaderWriter::ReadResult result = readImage(fileName, options);
429            if (!result.validImage()) return result;
430
431            osg::ref_ptr<osgWidget::VncClient> vncClient = new osgWidget::VncClient();
432            if (vncClient->assign(dynamic_cast<osgWidget::VncImage*>(result.getImage())))
433            {
434                return vncClient.release();
435            }
436            else
437            {
438                return osgDB::ReaderWriter::ReadResult::FILE_NOT_HANDLED;
439            }
440        }
441};
442
443// now register with Registry to instantiate the above
444// reader/writer.
445REGISTER_OSGPLUGIN(vnc, ReaderWriterVNC)
Note: See TracBrowser for help on using the browser.