/src/slg/telnet/telnet.cpp
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}