PageRenderTime 114ms CodeModel.GetById 2ms app.highlight 103ms RepoModel.GetById 1ms app.codeStats 1ms

/src/slg/telnet/telnet.cpp

https://bitbucket.org/luxrender/luxrays
C++ | 917 lines | 789 code | 52 blank | 76 comment | 316 complexity | b293ecde7363adcb2832f9a460d52c9c MD5 | raw file
  1/***************************************************************************
  2 *   Copyright (C) 1998-2013 by authors (see AUTHORS.txt)                  *
  3 *                                                                         *
  4 *   This file is part of LuxRays.                                         *
  5 *                                                                         *
  6 *   LuxRays is free software; you can redistribute it and/or modify       *
  7 *   it under the terms of the GNU General Public License as published by  *
  8 *   the Free Software Foundation; either version 3 of the License, or     *
  9 *   (at your option) any later version.                                   *
 10 *                                                                         *
 11 *   LuxRays is distributed in the hope that it will be useful,            *
 12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 14 *   GNU General Public License for more details.                          *
 15 *                                                                         *
 16 *   You should have received a copy of the GNU General Public License     *
 17 *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
 18 *                                                                         *
 19 *   LuxRays website: http://www.luxrender.net                             *
 20 ***************************************************************************/
 21
 22#include <iostream>
 23#include <string>
 24
 25#include <boost/asio.hpp>
 26#include <boost/thread/thread.hpp>
 27#include <boost/algorithm/string/split.hpp>
 28#include <boost/algorithm/string/classification.hpp>
 29#include <boost/algorithm/string/trim.hpp>
 30
 31#include "slg/telnet/telnet.h"
 32#include "slg/renderconfig.h"
 33
 34#include "luxrays/utils/properties.h"
 35
 36using namespace std;
 37using namespace luxrays;
 38using namespace slg;
 39
 40using boost::asio::ip::tcp;
 41
 42TelnetServer::TelnetServer(const unsigned int serverPort, RenderSession *renderSession) : port(serverPort) {
 43	session = renderSession;
 44	serverThread = new boost::thread(boost::bind(TelnetServer::ServerThreadImpl, this));
 45}
 46
 47TelnetServer::~TelnetServer() {
 48	serverThread->interrupt();
 49	serverThread->join();
 50}
 51
 52void TelnetServer::ServerThreadImpl(TelnetServer *telnetServer) {
 53	SLG_LOG("[Telnet server] Thread started");
 54
 55	try {
 56		ServerState state = RUN;
 57
 58		boost::asio::io_service ioService;
 59		tcp::acceptor acceptor(ioService, tcp::endpoint(tcp::v4(), telnetServer->port));
 60		SLG_LOG("[Telnet server] Server started on port: " << telnetServer->port);
 61
 62		for (;;) {
 63			tcp::socket socket(ioService);
 64			acceptor.accept(socket);
 65
 66			// Handle the connection
 67			try {
 68				boost::asio::streambuf response;
 69				std::ostream respStream(&response);
 70				respStream << "SmallLuxGPU Telnet Server Interface\n";
 71				boost::asio::write(socket, response);
 72
 73				bool echoCommandOn = true;
 74				for (bool exit = false; !exit;) {
 75					// Print prompt
 76					boost::asio::write(socket, boost::asio::buffer("> ", 2));
 77
 78					// Read the command
 79					boost::asio::streambuf commandBuf;
 80					boost::asio::read_until(socket, commandBuf, "\n");
 81
 82					std::istream commandStream(&commandBuf);
 83					string command;
 84					commandStream >> command;
 85					if (echoCommandOn)
 86						SLG_LOG("[Telnet server] Received command: " << command);
 87
 88					RenderSession *session = telnetServer->session;
 89					Scene *scene = session->renderConfig->scene;
 90					Film *film = session->film;
 91
 92					if (command == "exit")
 93						exit = true;
 94					else if (command == "help") {
 95						boost::asio::streambuf response;
 96						std::ostream respStream(&response);
 97						respStream << "exit - close the connection\n";
 98						respStream << "get <property name> - return the value of a (supported) property\n";
 99						respStream << "echocmd.off\n";
100						respStream << "echocmd.on\n";
101						respStream << "edit.start - start an editing session (alias render.start for SLG 1.x compatibility)\n";
102						respStream << "edit.stop - stop an editing session (alias render.stop for SLG 1.x compatibility)\n";
103						respStream << "help - this help\n";
104						respStream << "help.get - print the list of get supported properties\n";
105						respStream << "help.set - print the list of set supported properties\n";
106						respStream << "image.reset - reset the rendering image (requires edit.start)\n";
107						respStream << "image.save - save the rendering image\n";
108						respStream << "material.list - print the list of materials\n";
109						respStream << "object.list - print the list of objects\n";
110						respStream << "set <property name> = <values> - set the value of a (supported) property\n";
111						respStream << "set scene.materials.<name>.* = <values>, ... - update a material definition\n";
112						respStream << "transmit.framebuffer.rgb_float - transmit the current framebuffer (RGB float format)\n";
113						respStream << "transmit.framebuffer.rgb_byte - transmit the current framebuffer (RGB byte format)\n";
114						respStream << "OK\n";
115					    boost::asio::write(socket, response);
116					} else if (command == "echocmd.off") {
117						echoCommandOn = false;
118						boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
119					} else if (command == "echocmd.on") {
120						echoCommandOn = true;
121						boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
122					} else if (command == "get") {
123						//------------------------------------------------------
124						// Get property
125						//------------------------------------------------------
126
127						// Get the name of the property to recover
128						string property;
129						commandStream >> property;
130
131						// Check if is one of the supported properties
132						if (property == "film.tonemap.linear.scale") {
133							if (film->GetToneMapParams()->GetType() == TONEMAP_LINEAR) {
134								boost::asio::streambuf response;
135								std::ostream respStream(&response);
136								LinearToneMapParams *params = (LinearToneMapParams *)film->GetToneMapParams();
137								respStream << params->scale << "\n";
138								respStream << "OK\n";
139								boost::asio::write(socket, response);
140							} else {
141								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
142								SLG_LOG("[Telnet server] Not using TONEMAP_LINEAR");
143							}
144						} else if (property == "film.tonemap.reinhard02.burn") {
145							if (film->GetToneMapParams()->GetType() == TONEMAP_REINHARD02) {
146								boost::asio::streambuf response;
147								std::ostream respStream(&response);
148								Reinhard02ToneMapParams *params = (Reinhard02ToneMapParams *)film->GetToneMapParams();
149								respStream << params->burn << "\n";
150								respStream << "OK\n";
151								boost::asio::write(socket, response);
152							} else {
153								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
154								SLG_LOG("[Telnet server] Not using TONEMAP_REINHARD02");
155							}
156						} else if (property == "film.tonemap.reinhard02.postscale") {
157							if (film->GetToneMapParams()->GetType() == TONEMAP_REINHARD02) {
158								boost::asio::streambuf response;
159								std::ostream respStream(&response);
160								Reinhard02ToneMapParams *params = (Reinhard02ToneMapParams *)film->GetToneMapParams();
161								respStream << params->postScale << "\n";
162								respStream << "OK\n";
163								boost::asio::write(socket, response);
164							} else {
165								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
166								SLG_LOG("[Telnet server] Not using TONEMAP_REINHARD02");
167							}
168						} else if (property == "film.tonemap.reinhard02.prescale") {
169							if (film->GetToneMapParams()->GetType() == TONEMAP_REINHARD02) {
170								boost::asio::streambuf response;
171								std::ostream respStream(&response);
172								Reinhard02ToneMapParams *params = (Reinhard02ToneMapParams *)film->GetToneMapParams();
173								respStream << params->preScale << "\n";
174								respStream << "OK\n";
175								boost::asio::write(socket, response);
176							} else {
177								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
178								SLG_LOG("[Telnet server] Not using TONEMAP_REINHARD02");
179							}
180						} else if (property == "film.tonemap.type") {
181							boost::asio::streambuf response;
182							std::ostream respStream(&response);
183							respStream << film->GetToneMapParams()->GetType() << "\n";
184							respStream << "OK\n";
185							boost::asio::write(socket, response);
186						} else if (property == "scene.camera.lookat") {
187							boost::asio::streambuf response;
188							std::ostream respStream(&response);
189							const Point &o = scene->camera->orig;
190							const Point &t = scene->camera->target;
191							respStream << o.x << " " << o.y << " " << o.z << " "
192									<< t.x << " " << t.y << " " << t.z << "\n";
193							respStream << "OK\n";
194							boost::asio::write(socket, response);
195						} else if (property == "scene.camera.up") {
196							boost::asio::streambuf response;
197							std::ostream respStream(&response);
198							const Vector &up = scene->camera->up;
199							respStream << up.x << " " << up.y << " " << up.z << "\n";
200							respStream << "OK\n";
201							boost::asio::write(socket, response);
202						} else if (property == "scene.camera.lensradius") {
203							boost::asio::streambuf response;
204							std::ostream respStream(&response);
205							respStream << scene->camera->lensRadius << "\n";
206							respStream << "OK\n";
207							boost::asio::write(socket, response);
208						} else if (property == "scene.camera.fieldofview") {
209							boost::asio::streambuf response;
210							std::ostream respStream(&response);
211							respStream << scene->camera->fieldOfView << "\n";
212							respStream << "OK\n";
213							boost::asio::write(socket, response);
214						} else if (property == "scene.camera.focaldistance") {
215							boost::asio::streambuf response;
216							std::ostream respStream(&response);
217							respStream << scene->camera->focalDistance << "\n";
218							respStream << "OK\n";
219							boost::asio::write(socket, response);
220						} else if (property == "image.filename") {
221							boost::asio::streambuf response;
222							std::ostream respStream(&response);
223							respStream << session->renderConfig->cfg.GetString("image.filename", "image.png") << "\n";
224							respStream << "OK\n";
225							boost::asio::write(socket, response);
226						} else if (property == "scene.infinitelight.gain") {
227							InfiniteLight *il = (InfiniteLight *)scene->GetLightByType(TYPE_IL);
228							if (il) {
229								std::ostream respStream(&response);
230								const Spectrum gain = il->GetGain();
231								respStream << gain.r << " " << gain.g << " " << gain.b << "\n";
232								respStream << "OK\n";
233								boost::asio::write(socket, response);
234							} else {
235								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
236								SLG_LOG("[Telnet server] No InfiniteLight defined: " << property);
237							}
238						} else if (property == "scene.infinitelight.shift") {
239							InfiniteLight *il = (InfiniteLight *)scene->GetLightByType(TYPE_IL);
240							if (il) {
241								std::ostream respStream(&response);
242								respStream << il->GetUVMapping()->uDelta << " " <<
243										il->GetUVMapping()->vDelta << "\n";
244								respStream << "OK\n";
245								boost::asio::write(socket, response);
246							} else {
247								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
248								SLG_LOG("[Telnet server] No InfiniteLight defined: " << property);
249							}
250						} else if (property == "scene.skylight.dir") {
251							SkyLight *sl = (SkyLight *)scene->GetLightByType(TYPE_IL_SKY);
252							if (sl) {
253								std::ostream respStream(&response);
254								const Vector &dir = sl->GetSunDir();
255								respStream << dir.x << " " << dir.y << " " << dir.x << "\n";
256								respStream << "OK\n";
257								boost::asio::write(socket, response);
258							} else {
259								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
260								SLG_LOG("[Telnet server] No SkyLight defined: " << property);
261							}
262						} else if (property == "scene.skylight.gain") {
263							SkyLight *sl = (SkyLight *)scene->GetLightByType(TYPE_IL_SKY);
264							if (sl) {
265								std::ostream respStream(&response);
266								const Spectrum gain = sl->GetGain();
267								respStream << gain.r << " " << gain.g << " " << gain.b << "\n";
268								respStream << "OK\n";
269								boost::asio::write(socket, response);
270							} else {
271								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
272								SLG_LOG("[Telnet server] No SkyLight defined: " << property);
273							}
274						} else if (property == "scene.skylight.turbidity") {
275							SkyLight *sl = (SkyLight *)scene->GetLightByType(TYPE_IL_SKY);
276							if (sl) {
277								std::ostream respStream(&response);
278								respStream << sl->GetTubidity() << "\n";
279								respStream << "OK\n";
280								boost::asio::write(socket, response);
281							} else {
282								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
283								SLG_LOG("[Telnet server] No SkyLight defined: " << property);
284							}
285						} else if (property == "scene.sunlight.turbidity") {
286							// Look for the SunLight
287							SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
288							if (sl) {
289								std::ostream respStream(&response);
290								respStream << sl->GetTubidity() << "\n";
291								respStream << "OK\n";
292								boost::asio::write(socket, response);
293							} else {
294								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
295								SLG_LOG("[Telnet server] No SunLight defined: " << property);
296							}
297						} else if (property == "scene.sunlight.relsize") {
298							// Look for the SunLight
299							SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
300							if (sl) {
301								std::ostream respStream(&response);
302								respStream << sl->GetRelSize() << "\n";
303								respStream << "OK\n";
304								boost::asio::write(socket, response);
305							} else {
306								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
307								SLG_LOG("[Telnet server] No SunLight defined: " << property);
308							}
309						} else if (property == "scene.sunlight.dir") {
310							// Look for the SunLight
311							SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
312							if (sl) {
313								std::ostream respStream(&response);
314								const Vector &dir = sl->GetDir();
315								respStream << dir.x << " " << dir.y << " " << dir.x << "\n";
316								respStream << "OK\n";
317								boost::asio::write(socket, response);
318							} else {
319								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
320								SLG_LOG("[Telnet server] No SunLight defined: " << property);
321							}
322						} else if (property == "scene.sunlight.gain") {
323							// Look for the SunLight
324							SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
325							if (sl) {
326								std::ostream respStream(&response);
327								const Spectrum &gain = sl->GetGain();
328								respStream << gain.r << " " << gain.g << " " << gain.b << "\n";
329								respStream << "OK\n";
330								boost::asio::write(socket, response);
331							} else {
332								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
333								SLG_LOG("[Telnet server] No SunLight defined: " << property);
334							}
335						} else {
336							boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
337							SLG_LOG("[Telnet server] Unknown property: " << property);
338						}
339					} else if (command == "help.get") {
340						boost::asio::streambuf response;
341						std::ostream respStream(&response);
342						respStream << "film.tonemap.linear.scale\n";
343						respStream << "film.tonemap.reinhard02.burn\n";
344						respStream << "film.tonemap.reinhard02.postscale\n";
345						respStream << "film.tonemap.reinhard02.prescale\n";
346						respStream << "film.tonemap.type\n";
347						respStream << "image.filename\n";
348						respStream << "scene.camera.fieldofview\n";
349						respStream << "scene.camera.focaldistance\n";
350						respStream << "scene.camera.lensradius\n";
351						respStream << "scene.camera.lookat\n";
352						respStream << "scene.camera.up\n";
353						respStream << "scene.infinitelight.gain\n";
354						respStream << "scene.infinitelight.shift\n";
355						respStream << "scene.skylight.dir\n";
356						respStream << "scene.skylight.gain\n";
357						respStream << "scene.skylight.turbidity\n";
358						respStream << "scene.sunlight.dir\n";
359						respStream << "scene.sunlight.gain\n";
360						respStream << "scene.sunlight.relsize\n";
361						respStream << "scene.sunlight.turbidity\n";
362						respStream << "OK\n";
363						boost::asio::write(socket, response);
364					} else if (command == "help.set") {
365						boost::asio::streambuf response;
366						std::ostream respStream(&response);
367						respStream << "film.tonemap.linear.scale\n";
368						respStream << "film.tonemap.reinhard02.burn\n";
369						respStream << "film.tonemap.reinhard02.postscale\n";
370						respStream << "film.tonemap.reinhard02.prescale\n";
371						respStream << "film.tonemap.type\n";
372						respStream << "image.filename\n";
373						respStream << "scene.camera.fieldofview (requires edit.start)\n";
374						respStream << "scene.camera.focaldistance (requires edit.start)\n";
375						respStream << "scene.camera.lensradius (requires edit.start)\n";
376						respStream << "scene.camera.lookat (requires edit.start)\n";
377						respStream << "scene.camera.up (requires edit.start)\n";
378						respStream << "scene.materials.* (requires edit.start, comma separated list of properties)\n";
379						respStream << "scene.infinitelight.gain (requires edit.start)\n";
380						respStream << "scene.infinitelight.shift (requires edit.start)\n";
381						respStream << "scene.objects.*.transformation (requires edit.start)\n";
382						respStream << "scene.skylight.dir (requires edit.start)\n";
383						respStream << "scene.skylight.gain (requires edit.start)\n";
384						respStream << "scene.skylight.turbidity (requires edit.start)\n";
385						respStream << "scene.sunlight.dir (requires edit.start)\n";
386						respStream << "scene.sunlight.gain (requires edit.start)\n";
387						respStream << "scene.sunlight.relsize (requires edit.start)\n";
388						respStream << "scene.sunlight.turbidity (requires edit.start)\n";
389						respStream << "OK\n";
390						boost::asio::write(socket, response);
391					} else if (command == "image.reset") {
392						if (state == EDIT) {
393							session->film->Reset();
394							boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
395						} else {
396							boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
397							SLG_LOG("[Telnet server] Wrong state");
398						}
399					} else if (command == "material.list") {
400						boost::asio::streambuf response;
401						std::ostream respStream(&response);
402
403						std::vector<std::string> names = scene->matDefs.GetMaterialNames();
404						for (std::vector<std::string>::const_iterator iter = names.begin(); iter < names.end(); ++iter)
405							respStream << (*iter) << "\n";
406
407						respStream << "OK\n";
408						boost::asio::write(socket, response);
409					} else if (command == "object.list") {
410						boost::asio::streambuf response;
411						std::ostream respStream(&response);
412
413						std::vector<std::string> names = scene->meshDefs.GetExtMeshNames();
414						for (std::vector<std::string>::const_iterator iter = names.begin(); iter < names.end(); ++iter)
415							respStream << (*iter) << "\n";
416
417						respStream << "OK\n";
418						boost::asio::write(socket, response);
419					} else if (command == "image.save") {
420						session->SaveFilmImage();
421						boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
422					} else if ((command == "edit.stop") || (command == "render.start")) {
423						if (state == EDIT) {
424							if (session->editActions.Has(MATERIALS_EDIT)) {
425								session->renderConfig->scene->RemoveUnusedMaterials();
426								session->renderConfig->scene->RemoveUnusedTextures();
427							}
428							session->EndEdit();
429						}
430
431						state = RUN;
432						boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
433					} else if ((command == "edit.start") || (command == "render.stop")) {
434						if (state == RUN)
435							session->BeginEdit();
436						state = EDIT;
437						boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
438					} else if (command == "set") {
439						//------------------------------------------------------
440						// Set property
441						//------------------------------------------------------
442
443						try {
444							// Get the name of the property to set
445							string properties;
446							getline(commandStream, properties, '\n');
447							if (echoCommandOn)
448								SLG_LOG("[Telnet server] Set: " << properties);
449
450							// Split the line by comma
451							std::vector<std::string> splitProperties;
452							boost::split(splitProperties, properties, boost::is_any_of(","));
453							for (std::vector<std::string>::iterator it = splitProperties.begin(); it < splitProperties.end(); ++it)
454								boost::trim(*it);
455
456							// Build the Properties
457							Properties props;
458							const string propertyName = props.SetString(splitProperties[0]);
459							for (std::vector<std::string>::const_iterator it = splitProperties.begin() + 1; it < splitProperties.end(); ++it)
460								props.SetString(*it);
461
462							// Check if is one of the supported properties
463							if (propertyName == "film.tonemap.linear.scale") {
464								const float k = props.GetFloat(propertyName, 1.f);
465
466								if (film->GetToneMapParams()->GetType() == TONEMAP_LINEAR) {
467									boost::asio::streambuf response;
468									std::ostream respStream(&response);
469									LinearToneMapParams *params = (LinearToneMapParams *)film->GetToneMapParams()->Copy();
470									params->scale = k;
471									film->SetToneMapParams(*params);
472									delete params;
473									respStream << "OK\n";
474									boost::asio::write(socket, response);
475								} else {
476									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
477									SLG_LOG("[Telnet server] Not using TONEMAP_REINHARD02");
478								}
479							} else if (propertyName == "film.tonemap.reinhard02.burn") {
480								const float k = props.GetFloat(propertyName, 3.75f);
481
482								if (film->GetToneMapParams()->GetType() == TONEMAP_REINHARD02) {
483									boost::asio::streambuf response;
484									std::ostream respStream(&response);
485									Reinhard02ToneMapParams *params = (Reinhard02ToneMapParams *)film->GetToneMapParams()->Copy();
486									params->burn = k;
487									film->SetToneMapParams(*params);
488									delete params;
489									respStream << "OK\n";
490									boost::asio::write(socket, response);
491								} else {
492									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
493									SLG_LOG("[Telnet server] Not using TONEMAP_REINHARD02");
494								}
495							} else if (propertyName == "film.tonemap.reinhard02.postscale") {
496								const float k = props.GetFloat(propertyName, 1.2f);
497
498								if (film->GetToneMapParams()->GetType() == TONEMAP_REINHARD02) {
499									boost::asio::streambuf response;
500									std::ostream respStream(&response);
501									Reinhard02ToneMapParams *params = (Reinhard02ToneMapParams *)film->GetToneMapParams()->Copy();
502									params->postScale = k;
503									film->SetToneMapParams(*params);
504									delete params;
505									respStream << "OK\n";
506									boost::asio::write(socket, response);
507								} else {
508									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
509									SLG_LOG("[Telnet server] Not using TONEMAP_REINHARD02");
510								}
511							} else if (propertyName == "film.tonemap.reinhard02.prescale") {
512								const float k = props.GetFloat(propertyName, 1.f);
513
514								if (film->GetToneMapParams()->GetType() == TONEMAP_REINHARD02) {
515									boost::asio::streambuf response;
516									std::ostream respStream(&response);
517									Reinhard02ToneMapParams *params = (Reinhard02ToneMapParams *)film->GetToneMapParams()->Copy();
518									params->preScale = k;
519									film->SetToneMapParams(*params);
520									delete params;
521									respStream << "OK\n";
522									boost::asio::write(socket, response);
523								} else {
524									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
525									SLG_LOG("[Telnet server] Not using TONEMAP_REINHARD02");
526								}
527							} else if (propertyName == "film.tonemap.type") {
528								const int type = props.GetInt(propertyName, 0);
529
530								if (type == 0) {
531									LinearToneMapParams params;
532									film->SetToneMapParams(params);
533								} else {
534									Reinhard02ToneMapParams params;
535									film->SetToneMapParams(params);
536								}
537
538								respStream << "OK\n";
539								boost::asio::write(socket, response);
540							} else if (propertyName == "image.filename") {
541								// Get the image file name
542								const string fileName = props.GetString(propertyName, "image.png");
543
544								session->renderConfig->cfg.SetString("image.filename", fileName);
545								respStream << "OK\n";
546								boost::asio::write(socket, response);
547							} else if (propertyName == "scene.infinitelight.gain") {
548								// Check if we are in the right state
549								if (state == EDIT) {
550									InfiniteLight *il = (InfiniteLight *)scene->GetLightByType(TYPE_IL);
551									if (il) {
552										const std::vector<float> vf = props.GetFloatVector(propertyName, "1.0 1.0 1.0");
553										Spectrum gain(vf.at(0), vf.at(1), vf.at(2));
554										il->SetGain(gain);
555										session->editActions.AddAction(INFINITELIGHT_EDIT);
556										respStream << "OK\n";
557										boost::asio::write(socket, response);
558									} else {
559										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
560										SLG_LOG("[Telnet server] No InifinteLight defined: " << properties);
561									}
562								} else {
563									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
564									SLG_LOG("[Telnet server] Wrong state: " << properties);
565								}
566							} else if (propertyName == "scene.infinitelight.shift") {
567								// Check if we are in the right state
568								if (state == EDIT) {
569									InfiniteLight *il = (InfiniteLight *)scene->GetLightByType(TYPE_IL);
570									if (il) {
571										const std::vector<float> vf = props.GetFloatVector(propertyName, "0.0 0.0");
572										il->GetUVMapping()->uDelta = vf.at(0);
573										il->GetUVMapping()->vDelta = vf.at(1);
574										session->editActions.AddAction(INFINITELIGHT_EDIT);
575										respStream << "OK\n";
576										boost::asio::write(socket, response);
577									} else {
578										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
579										SLG_LOG("[Telnet server] No InifinteLight defined: " << properties);
580									}
581								} else {
582									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
583									SLG_LOG("[Telnet server] Wrong state: " << properties);
584								}
585							} else if (propertyName == "scene.skylight.dir") {
586								// Check if we are in the right state
587								if (state == EDIT) {
588									SkyLight *sl = (SkyLight *)scene->GetLightByType(TYPE_IL_SKY);
589									if (sl) {
590										const std::vector<float> vf = props.GetFloatVector(propertyName, "0.0 0.0 1.0");
591										Vector dir(vf.at(0), vf.at(1), vf.at(2));
592										sl->SetSunDir(dir);
593										sl->Preprocess();
594										session->editActions.AddAction(SKYLIGHT_EDIT);
595										respStream << "OK\n";
596										boost::asio::write(socket, response);
597									} else {
598										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
599										SLG_LOG("[Telnet server] No SkyLight defined: " << properties);
600									}
601								} else {
602									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
603									SLG_LOG("[Telnet server] Wrong state: " << properties);
604								}
605							} else if (propertyName == "scene.skylight.gain") {
606								// Check if we are in the right state
607								if (state == EDIT) {
608									SkyLight *sl = (SkyLight *)scene->GetLightByType(TYPE_IL_SKY);
609									if (sl) {
610										const std::vector<float> vf = props.GetFloatVector(propertyName, "1.0 1.0 1.0");
611										Spectrum gain(vf.at(0), vf.at(1), vf.at(2));
612										sl->SetGain(gain);
613										session->editActions.AddAction(SKYLIGHT_EDIT);
614										respStream << "OK\n";
615										boost::asio::write(socket, response);
616									} else {
617										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
618										SLG_LOG("[Telnet server] No SkyLight defined: " << properties);
619									}
620								} else {
621									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
622									SLG_LOG("[Telnet server] Wrong state: " << properties);
623								}
624							} else if (propertyName == "scene.skylight.turbidity") {
625								// Check if we are in the right state
626								if (state == EDIT) {
627									SkyLight *sl = (SkyLight *)scene->GetLightByType(TYPE_IL_SKY);
628									if (sl) {
629										sl->SetTurbidity(props.GetFloat(propertyName, 2.2f));
630										sl->Preprocess();
631										session->editActions.AddAction(SKYLIGHT_EDIT);
632										respStream << "OK\n";
633										boost::asio::write(socket, response);
634									} else {
635										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
636										SLG_LOG("[Telnet server] No SkyLight defined: " << properties);
637									}
638								} else {
639									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
640									SLG_LOG("[Telnet server] Wrong state: " << properties);
641								}
642							} else if (propertyName == "scene.sunlight.turbidity") {
643								if (state == EDIT) {
644									// Look for the SunLight
645									SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
646									if (sl) {
647										sl->SetTurbidity(props.GetFloat(propertyName, 2.2f));
648										sl->Preprocess();
649										session->editActions.AddAction(SUNLIGHT_EDIT);
650										respStream << "OK\n";
651										boost::asio::write(socket, response);
652									} else {
653										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
654										SLG_LOG("[Telnet server] No SunLight defined: " << properties);
655									}
656								} else {
657									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
658									SLG_LOG("[Telnet server] Wrong state: " << properties);
659								}
660							} else if (propertyName == "scene.sunlight.relsize") {
661								if (state == EDIT) {
662									// Look for the SunLight
663									SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
664									if (sl) {
665										sl->SetRelSize(props.GetFloat(propertyName, 1.f));
666										sl->Preprocess();
667										session->editActions.AddAction(SUNLIGHT_EDIT);
668										respStream << "OK\n";
669										boost::asio::write(socket, response);
670									} else {
671										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
672										SLG_LOG("[Telnet server] No SunLight defined: " << properties);
673									}
674								} else {
675									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
676									SLG_LOG("[Telnet server] Wrong state: " << properties);
677								}
678							} else if (propertyName == "scene.sunlight.dir") {
679								if (state == EDIT) {
680									// Look for the SunLight
681									SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
682									if (sl) {
683										const std::vector<float> vf = props.GetFloatVector(propertyName, "0.0 0.0 1.0");
684										Vector dir(vf.at(0), vf.at(1), vf.at(2));
685										sl->SetDir(dir);
686										sl->Preprocess();
687										session->editActions.AddAction(SUNLIGHT_EDIT);
688										respStream << "OK\n";
689										boost::asio::write(socket, response);
690									} else {
691										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
692										SLG_LOG("[Telnet server] No SunLight defined: " << properties);
693									}
694								} else {
695									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
696									SLG_LOG("[Telnet server] Wrong state: " << properties);
697								}
698							} else if (propertyName == "scene.sunlight.gain") {
699								if (state == EDIT) {
700									// Look for the SunLight
701									SunLight *sl = (SunLight *)scene->GetLightByType(TYPE_SUN);
702									if (sl) {
703										const std::vector<float> vf = props.GetFloatVector(propertyName, "1.0 1.0 1.0");
704										Spectrum gain(vf.at(0), vf.at(1), vf.at(2));
705										sl->SetGain(gain);
706										sl->Preprocess();
707										session->editActions.AddAction(SUNLIGHT_EDIT);
708										respStream << "OK\n";
709										boost::asio::write(socket, response);
710									} else {
711										boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
712										SLG_LOG("[Telnet server] No SunLight defined: " << properties);
713									}
714								} else {
715									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
716									SLG_LOG("[Telnet server] Wrong state: " << properties);
717								}
718							} else if (propertyName.find("scene.materials.") == 0) {
719								if (state == EDIT) {
720									// Check if it is the name of a known material
721									const std::string matName = Properties::ExtractField(propertyName, 2);
722									if (matName == "")
723										throw std::runtime_error("Syntax error in " + propertyName);
724
725									// Update material definition
726									scene->UpdateMaterial(matName, props);
727									const Material *newMat = scene->matDefs.GetMaterial(matName);
728
729									// To enable this optimization, I should check not only all
730									// referenced materials (i.e. Mix) but also all referenced textures.
731									// Doesn't seem worth the work.
732									//// Check if the material type is one of the already enabled
733									//if (!session->renderEngine->IsMaterialCompiled(newMat->GetType()))
734										session->editActions.AddAction(MATERIAL_TYPES_EDIT);
735									// Check if both are light sources
736									if (newMat->IsLightSource())
737										session->editActions.AddAction(AREALIGHTS_EDIT);
738
739									session->editActions.AddAction(MATERIALS_EDIT);
740
741									boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
742								} else {
743									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
744									SLG_LOG("[Telnet server] Wrong state: " << properties);
745								}
746							} else if ((propertyName.find("scene.objects.") == 0) && (propertyName.find(".transformation") == propertyName.size() - 15)) {
747								if (state == EDIT) {
748									// Check if it is the name of a known objects
749									const std::string objName = Properties::ExtractField(propertyName, 2);
750									if (objName == "")
751										throw std::runtime_error("Syntax error in " + propertyName);
752
753									// Read the new transformation
754									const std::vector<float> vf = props.GetFloatVector(propertyName,
755											"1.0 0.0 0.0 0.0  0.0 1.0 0.0 0.0  0.0 0.0 1.0 0.0  0.0 0.0 0.0 1.0");
756									const Matrix4x4 mat(
757											vf.at(0), vf.at(4), vf.at(8), vf.at(12),
758											vf.at(1), vf.at(5), vf.at(9), vf.at(13),
759											vf.at(2), vf.at(6), vf.at(10), vf.at(14),
760											vf.at(3), vf.at(7), vf.at(11), vf.at(15));
761									const Transform trans(mat);
762
763									// Update object transformation
764									scene->UpdateObjectTransformation(objName, trans);
765
766									// Check if it is a light source
767									const u_int meshIndex = scene->meshDefs.GetExtMeshIndex(objName);
768									if (scene->objectMaterials[meshIndex]->IsLightSource()) {
769										// Some render engine requires a complete update when
770										// modifying a light source
771										session->editActions.AddAction(AREALIGHTS_EDIT);
772									}
773
774									// Set the flag to Update the DataSet
775									ExtMesh *mesh = scene->meshDefs.GetExtMesh(objName);
776									if (mesh->GetType() == TYPE_EXT_TRIANGLE_INSTANCE)
777										session->editActions.AddAction(INSTANCE_TRANS_EDIT);
778									else
779										session->editActions.AddAction(GEOMETRY_EDIT);
780
781									boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
782								} else {
783									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
784									SLG_LOG("[Telnet server] Wrong state: " << properties);
785								}
786							} else if (propertyName == "scene.camera.lookat") {
787								// Check if we are in the right state
788								if (state == EDIT) {
789									const std::vector<float> vf = props.GetFloatVector(propertyName, "10.0 0.0 0.0  0.0 0.0 0.0");
790									Point o(vf.at(0), vf.at(1), vf.at(2));
791									Point t(vf.at(3), vf.at(4), vf.at(5));
792
793									scene->camera->orig = o;
794									scene->camera->target = t;
795									scene->camera->Update(film->GetWidth(),
796											film->GetHeight());
797									session->editActions.AddAction(CAMERA_EDIT);
798									boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
799								} else {
800									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
801									SLG_LOG("[Telnet server] Wrong state: " << properties);
802								}
803							} else if (propertyName == "scene.camera.up") {
804								// Check if we are in the right state
805								if (state == EDIT) {
806									const std::vector<float> vf = props.GetFloatVector(propertyName, "0.0 0.0 0.1");
807									Vector up(vf.at(0), vf.at(1), vf.at(2));
808
809									scene->camera->up = Normalize(up);
810									scene->camera->Update(film->GetWidth(),
811											film->GetHeight());
812									session->editActions.AddAction(CAMERA_EDIT);
813									boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
814								} else {
815									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
816									SLG_LOG("[Telnet server] Wrong state: " << properties);
817								}
818							} else if (propertyName == "scene.camera.lensradius") {
819								// Check if we are in the right state
820								if (state == EDIT) {
821									scene->camera->lensRadius = props.GetFloat(propertyName, 0.f);
822									scene->camera->Update(film->GetWidth(),
823											film->GetHeight());
824									session->editActions.AddAction(CAMERA_EDIT);
825									boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
826								} else {
827									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
828									SLG_LOG("[Telnet server] Wrong state: " << properties);
829								}
830							} else if (propertyName == "scene.camera.fieldofview") {
831								// Check if we are in the right state
832								if (state == EDIT) {
833									scene->camera->fieldOfView = props.GetFloat(propertyName, 0.f);
834									scene->camera->Update(film->GetWidth(),
835											film->GetHeight());
836									session->editActions.AddAction(CAMERA_EDIT);
837									boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
838								} else {
839									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
840									SLG_LOG("[Telnet server] Wrong state: " << properties);
841								}
842							} else if (propertyName == "scene.camera.focaldistance") {
843								// Check if we are in the right state
844								if (state == EDIT) {
845									scene->camera->focalDistance = props.GetFloat(propertyName, 0.f);
846									scene->camera->Update(film->GetWidth(),
847											film->GetHeight());
848									session->editActions.AddAction(CAMERA_EDIT);
849									boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
850								} else {
851									boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
852									SLG_LOG("[Telnet server] Wrong state: " << properties);
853								}
854							} else {
855								boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
856								SLG_LOG("[Telnet server] Unknown property: " << properties);
857							}
858						} catch (std::exception& e) {
859							boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
860							SLG_LOG("[Telnet server] Error while setting a property: " << e.what());
861						}
862					} else if ((command == "transmit.framebuffer.rgb_float")) {
863						// Lock the film
864						{
865							boost::unique_lock<boost::mutex> lock(session->filmMutex);
866
867							// Transmit the image size
868							const unsigned int w = film->GetWidth();
869							const unsigned int h = film->GetHeight();
870							boost::asio::write(socket, boost::asio::buffer(boost::asio::const_buffer(&w, sizeof(unsigned int))));
871							boost::asio::write(socket, boost::asio::buffer(boost::asio::const_buffer(&h, sizeof(unsigned int))));
872
873							// Transmit the framebuffer (RGB float)
874							boost::asio::write(socket, boost::asio::buffer(boost::asio::const_buffer(session->film->GetScreenBuffer(),
875									sizeof(float) * w * h * 3)));
876						}
877						boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
878					} else if ((command == "transmit.framebuffer.rgb_byte")) {
879						// Lock the film
880						{
881							boost::unique_lock<boost::mutex> lock(session->filmMutex);
882
883							// Transmit the image size
884							const unsigned int w = film->GetWidth();
885							const unsigned int h = film->GetHeight();
886							boost::asio::write(socket, boost::asio::buffer(boost::asio::const_buffer(&w, sizeof(unsigned int))));
887							boost::asio::write(socket, boost::asio::buffer(boost::asio::const_buffer(&h, sizeof(unsigned int))));
888
889							// Translate the framebuffer
890							unsigned char *fb = new unsigned char[w * h * 3];
891							unsigned char *dst = fb;
892							const float *src = session->film->GetScreenBuffer();
893							for (unsigned int i = 0; i < w * h; ++i) {
894								*dst++ = (*src++) * 255.f + .5f;
895								*dst++ = (*src++) * 255.f + .5f;
896								*dst++ = (*src++) * 255.f + .5f;
897							}
898
899							// Transmit the framebuffer (RGB byte)
900							boost::asio::write(socket, boost::asio::buffer(boost::asio::const_buffer(fb,
901									sizeof(unsigned char) * w * h * 3)));
902							delete fb;
903						}
904						boost::asio::write(socket, boost::asio::buffer("OK\n", 3));
905					} else {
906						boost::asio::write(socket, boost::asio::buffer("ERROR\n", 6));
907						SLG_LOG("[Telnet server] Unknown command");
908					}
909				}
910			} catch (std::exception& e) {
911				SLG_LOG("[Telnet server] Connection error: " << e.what());
912			}
913		}
914	} catch (std::exception& e) {
915		SLG_LOG("Telnet server error: " << e.what());
916	}
917}