Fix crash
[ryzomcore.git] / snowballs2 / client / src / commands.cpp
blob5234fcfacf0220823f8e097c5232132e755dd16c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 // Includes
24 #include <nel/misc/types_nl.h>
26 #include <list>
28 #include <nel/misc/event_listener.h>
29 #include <nel/misc/command.h>
30 #include <nel/misc/log.h>
31 #include <nel/misc/displayer.h>
33 #include <nel/3d/u_camera.h>
34 #include <nel/3d/u_driver.h>
35 #include <nel/3d/u_text_context.h>
36 #include <nel/3d/u_instance.h>
37 #include <nel/3d/u_scene.h>
38 #include <nel/3d/u_3d_mouse_listener.h>
39 #include <nel/3d/u_material.h>
40 #include <nel/3d/u_landscape.h>
41 #include <nel/3d/stereo_hmd.h>
43 #include "network.h"
44 #include "snowballs_client.h"
45 #include "interface.h"
47 #if SBCLIENT_DEV_PIXEL_PROGRAM
48 #include <nel/3d/driver_user.h>
49 #include <nel/3d/driver.h>
50 #include <nel/3d/pixel_program.h>
51 #include <nel/3d/material.h>
52 #include <nel/3d/u_texture.h>
53 #endif
56 // Namespaces
59 using namespace std;
60 using namespace NLMISC;
61 using namespace NL3D;
63 namespace SBCLIENT {
66 // Variables
69 CLog CommandsLog;
71 static list <string> StoredLines;
72 static uint32 NbStoredLines = 100;
74 // These variables are automatically set with the config file
76 static float CommandsBoxX, CommandsBoxY, CommandsBoxWidth;
77 static float CommandsBoxBorder;
78 static int CommandsNbLines;
79 static float CommandsLineHeight;
80 static int CommandsFontSize;
81 static CRGBA CommandsBackColor, CommandsFrontColor;
82 static UMaterial CommandsMaterial = NULL;
85 // Functions
88 // Display a string to the commands interface
89 void addLine (const string &line)
91 // Add the line
92 StoredLines.push_back (line);
94 // Clear old lines if too much lines are stored
95 while (StoredLines.size () > NbStoredLines)
97 StoredLines.pop_front ();
101 // Display used to display on the commands interface
102 class CCommandsDisplayer : public IDisplayer
104 virtual void doDisplay (const CLog::TDisplayInfo &args, const char *message)
106 bool needSpace = false;
107 string str;
109 if (args.LogType != CLog::LOG_NO)
111 str += logTypeToString(args.LogType);
112 needSpace = true;
115 if (needSpace) { str += ": "; needSpace = false; }
116 str += message;
117 addLine (str);
121 // Instance of the displayer
122 static CCommandsDisplayer CommandsDisplayer;
124 // Check if the user line is a command or not (a commands precede by a '/')
125 bool commandLine (const string &str)
127 string command = "";
129 if (str[0]=='/')
131 // If it's a command call it
132 command = str.substr(1);
133 // add the string in to the chat
134 addLine (string ("command> ") + str);
135 ICommand::execute (command, CommandsLog);
136 return true;
138 else
140 return false;
144 // Manage the user keyboard input
145 class CCommandsListener : public IEventListener
147 virtual void operator() ( const CEvent& event )
149 // If the interface is open, ignore keys for the command interface
150 if (interfaceOpen ()) return;
152 // Get the key
153 CEventChar &ec = (CEventChar&)event;
155 switch ( ec.Char )
157 case 13 : // RETURN : Send the chat message
159 // If the line is empty, do nothing
160 if ( _Line.size() == 0 ) break;
162 // If it's a command, execute it and don't send the command to the network
163 if ( ! commandLine( _Line ) )
165 // If online, send the chat line, otherwise, locally displays it
166 if (isOnline ())
167 sendChatLine (_Line);
168 else
169 addLine (string ("you said> ") + _Line);
171 // Reset the command line
172 _LastCommand = _Line;
173 _Line = "";
174 _MaxWidthReached = false;
175 break;
177 case 8 : // BACKSPACE : remove the last character
179 if ( _Line.size() != 0 )
181 _Line.erase( _Line.end()-1 );
183 break;
185 case 9 : // TAB : If it's a command, try to auto complete it
187 if (_Line.empty())
189 _Line = _LastCommand;
191 else if (!_Line.empty() && _Line[0] == '/')
193 string command = _Line.substr(1);
194 ICommand::expand(command);
195 _Line = '/' + command;
197 break;
199 case 27 : // ESCAPE : clear the command
201 _Line = "";
202 _MaxWidthReached = false;
203 break;
205 default: // OTHERWISE : add the character to the line
207 if (! _MaxWidthReached)
209 _Line += (char)ec.Char;
214 public:
215 CCommandsListener() : _MaxWidthReached( false )
218 const string& line() const
220 return _Line;
223 void setMaxWidthReached( bool b )
225 _MaxWidthReached = b;
228 private:
229 string _Line;
230 bool _MaxWidthReached;
231 string _LastCommand;
234 // Instance of the listener
235 static CCommandsListener CommandsListener;
237 // This functions is automatically called when the config file changed (dynamically)
238 void cbUpdateCommands (CConfigFile::CVar &var)
240 if (var.Name == "CommandsBoxX") CommandsBoxX = var.asFloat ();
241 else if (var.Name == "CommandsBoxY") CommandsBoxY = var.asFloat ();
242 else if (var.Name == "CommandsBoxWidth") CommandsBoxWidth = var.asFloat ();
243 else if (var.Name == "CommandsBoxBorder") CommandsBoxBorder = var.asFloat ();
244 else if (var.Name == "CommandsNbLines") CommandsNbLines = var.asInt ();
245 else if (var.Name == "CommandsLineHeight") CommandsLineHeight = var.asFloat ();
246 else if (var.Name == "CommandsBackColor") CommandsBackColor.set (var.asInt(0), var.asInt(1), var.asInt(2), var.asInt(3));
247 else if (var.Name == "CommandsFrontColor") CommandsFrontColor.set (var.asInt(0), var.asInt(1), var.asInt(2), var.asInt(3));
248 else if (var.Name == "CommandsFontSize") CommandsFontSize = var.asInt ();
249 else nlwarning ("Unknown variable update %s", var.Name.c_str());
252 #if SBCLIENT_DEV_PIXEL_PROGRAM
253 namespace {
254 CPixelProgram *a_DevPixelProgram = NULL;
255 UTextureFile *a_NelLogo;
257 #endif
259 void initCommands()
261 // Add the keyboard listener in the event server
262 Driver->EventServer.addListener (EventCharId, &CommandsListener);
264 // Add the command displayer to the standard log (to display NeL info)
265 CommandsLog.addDisplayer (&CommandsDisplayer);
266 #ifndef NL_RELEASE
267 DebugLog->addDisplayer (&CommandsDisplayer);
268 InfoLog->addDisplayer (&CommandsDisplayer);
269 WarningLog->addDisplayer (&CommandsDisplayer);
270 AssertLog->addDisplayer (&CommandsDisplayer);
271 ErrorLog->addDisplayer (&CommandsDisplayer);
272 #endif
274 // Add callback for the config file
275 ConfigFile->setCallback ("CommandsBoxX", cbUpdateCommands);
276 ConfigFile->setCallback ("CommandsBoxY", cbUpdateCommands);
277 ConfigFile->setCallback ("CommandsBoxWidth", cbUpdateCommands);
278 ConfigFile->setCallback ("CommandsBoxBorder", cbUpdateCommands);
279 ConfigFile->setCallback ("CommandsNbLines", cbUpdateCommands);
280 ConfigFile->setCallback ("CommandsLineHeight", cbUpdateCommands);
281 ConfigFile->setCallback ("CommandsBackColor", cbUpdateCommands);
282 ConfigFile->setCallback ("CommandsFrontColor", cbUpdateCommands);
283 ConfigFile->setCallback ("CommandsFontSize", cbUpdateCommands);
285 // Init the config file variable
286 cbUpdateCommands (ConfigFile->getVar ("CommandsBoxX"));
287 cbUpdateCommands (ConfigFile->getVar ("CommandsBoxY"));
288 cbUpdateCommands (ConfigFile->getVar ("CommandsBoxWidth"));
289 cbUpdateCommands (ConfigFile->getVar ("CommandsBoxBorder"));
290 cbUpdateCommands (ConfigFile->getVar ("CommandsNbLines"));
291 cbUpdateCommands (ConfigFile->getVar ("CommandsLineHeight"));
292 cbUpdateCommands (ConfigFile->getVar ("CommandsBackColor"));
293 cbUpdateCommands (ConfigFile->getVar ("CommandsFrontColor"));
294 cbUpdateCommands (ConfigFile->getVar ("CommandsFontSize"));
296 CommandsMaterial = Driver->createMaterial();
297 CommandsMaterial.initUnlit();
298 CommandsMaterial.setBlendFunc(UMaterial::srcalpha, UMaterial::invsrcalpha);
299 CommandsMaterial.setBlend(true);
301 #if SBCLIENT_DEV_PIXEL_PROGRAM
302 CommandsMaterial.getObjectPtr()->setShader(NL3D::CMaterial::Program);
303 a_NelLogo = Driver->createTextureFile("nel128.tga");
304 CommandsMaterial.setTexture(dynamic_cast<NL3D::UTexture *>(a_NelLogo));
305 static const char *program_arbfp1 =
306 "!!ARBfp1.0\n"
307 "PARAM c[1] = { { 1, 0 } };\n"
308 "MOV result.color.xzw, c[0].xyyx;\n"
309 "TEX result.color.y, fragment.texcoord[0], texture[0], 2D;\n"
310 "END\n";
311 static const char *program_fp40 =
312 "!!ARBfp1.0\n"
313 "OPTION NV_fragment_program2;\n"
314 "PARAM c[1] = { { 1, 0 } };\n"
315 "TEMP RC;\n"
316 "TEMP HC;\n"
317 "OUTPUT oCol = result.color;\n"
318 "MOVR oCol.xzw, c[0].xyyx;\n"
319 "TEX oCol.y, fragment.texcoord[0], texture[0], 2D;\n"
320 "END\n";
321 static const char *program_ps_1_1 =
322 "ps.1.1\n"
323 "def c0, 0.000000, 0.000000, 1.000000, 0.000000\n"
324 "def c1, 1.000000, 0.000000, 0.000000, 0.000000\n"
325 "def c2, 0.000000, 1.000000, 0.000000, 0.000000\n"
326 "tex t0\n"
327 "mad r0.rgb, c2, t0, c1\n"
328 "mov r0.a, c0.b\n";
329 static const char *program_ps_2_0 =
330 "ps_2_0\n"
331 "dcl_2d s0\n"
332 "def c0, 1.00000000, 0.00000000, 0, 0\n"
333 "dcl t0.xy\n"
334 "texld r0, t0, s0\n"
335 "mov r0.z, c0.y\n"
336 "mov r0.xw, c0.x\n"
337 "mov oC0, r0\n";
338 static const char *program_ps_3_0 =
339 "ps_3_0\n"
340 "dcl_2d s0\n"
341 "def c0, 1.00000000, 0.00000000, 0, 0\n"
342 "dcl_texcoord0 v0.xy\n"
343 "mov oC0.xzw, c0.xyyx\n"
344 "texld oC0.y, v0, s0\n";
345 NL3D::IDriver *d = dynamic_cast<NL3D::CDriverUser *>(Driver)->getDriver();
346 a_DevPixelProgram = new CPixelProgram();
347 // arbfp1
349 IProgram::CSource *source = new IProgram::CSource();
350 source->Features.MaterialFlags = CProgramFeatures::TextureStages;
351 source->Profile = IProgram::arbfp1;
352 source->setSourcePtr(program_arbfp1);
353 a_DevPixelProgram->addSource(source);
355 // ps_2_0
357 IProgram::CSource *source = new IProgram::CSource();
358 source->Features.MaterialFlags = CProgramFeatures::TextureStages;
359 source->Profile = IProgram::ps_2_0;
360 source->setSourcePtr(program_ps_2_0);
361 a_DevPixelProgram->addSource(source);
363 /*if (d->supportPixelProgram(CPixelProgram::fp40))
365 nldebug("fp40");
366 a_DevPixelProgram = new CPixelProgram(program_fp40);
368 else if (d->supportPixelProgram(CPixelProgram::arbfp1))
370 nldebug("arbfp1");
371 a_DevPixelProgram = new CPixelProgram(program_arbfp1);
373 /*else if (d->supportPixelProgram(CPixelProgram::ps_3_0))
375 nldebug("ps_3_0");
376 a_DevPixelProgram = new CPixelProgram(program_ps_3_0);
377 // Textures do not seem to work with ps_3_0...
379 /*else if (d->supportPixelProgram(CPixelProgram::ps_2_0))
381 nldebug("ps_2_0");
382 a_DevPixelProgram = new CPixelProgram(program_ps_2_0);
384 else if (d->supportPixelProgram(CPixelProgram::ps_1_1))
386 nldebug("ps_1_1");
387 a_DevPixelProgram = new CPixelProgram(program_ps_1_1);
389 #endif
392 void updateCommands()
394 // Snap to pixels (kind of ugly code, but looks better ingame)
395 uint32 _width, _height;
396 Driver->getWindowSize(_width, _height);
397 float width = (float)_width, height = (float)_height;
398 NL3D::CViewport vp = Driver->getViewport();
399 width *= vp.getWidth();
400 height *= vp.getHeight();
401 float CommandsLineHeight = CommandsFontSize / height;
402 float CommandsBoxX = ((float)(sint32)(SBCLIENT::CommandsBoxX * width)) / width;
403 float CommandsBoxWidth = ((float)(sint32)(SBCLIENT::CommandsBoxWidth * width)) / width;
404 float CommandsBoxY = ((float)(sint32)(SBCLIENT::CommandsBoxY * height)) / height;
405 float CommandsBoxHeight = ((float)(sint32)((CommandsNbLines + 1) * CommandsLineHeight * width)) / width;
406 float CommandsBoxBorderX = ((float)(sint32)(SBCLIENT::CommandsBoxBorder * width)) / width;
407 float CommandsBoxBorderY = ((float)(sint32)(SBCLIENT::CommandsBoxBorder * height)) / height;
409 // Display the background
410 Driver->setMatrixMode2D11 ();
411 #if SBCLIENT_DEV_PIXEL_PROGRAM
412 CommandsMaterial.setColor(CRGBA::Blue); // Test to check which shader is displaying.
413 #else
414 CommandsMaterial.setColor(CommandsBackColor);
415 #endif
416 float x0 = CommandsBoxX - CommandsBoxBorderX;
417 float y0 = CommandsBoxY - CommandsBoxBorderY;
418 float x1 = CommandsBoxX + CommandsBoxWidth + CommandsBoxBorderX;
419 float y1 = CommandsBoxY + CommandsBoxHeight + CommandsBoxBorderY;
421 #if SBCLIENT_DEV_PIXEL_PROGRAM
422 NL3D::IDriver *d = dynamic_cast<NL3D::CDriverUser *>(Driver)->getDriver();
423 d->activePixelProgram(a_DevPixelProgram);
424 bool fogEnabled = d->fogEnabled();
425 d->enableFog(false);
427 // Driver->drawQuad(CQuad(CVector(x0, y0, 0), CVector(x1, y0, 0), CVector(x1, y1, 0), CVector(x0, y1, 0)), CommandsMaterial);
428 CQuadUV quadUV;
429 quadUV.V0 = CVector(x0, y0, 0);
430 quadUV.V1 = CVector(x1, y0, 0);
431 quadUV.V2 = CVector(x1, y1, 0);
432 quadUV.V3 = CVector(x0, y1, 0);
433 quadUV.Uv0 = CUV(0, 1);
434 quadUV.Uv1 = CUV(1, 1);
435 quadUV.Uv2 = CUV(1, 0);
436 quadUV.Uv3 = CUV(0, 0);
437 Driver->drawQuad(quadUV, CommandsMaterial);
438 //Driver->drawBitmap(x0, y0, x1 - x0, y1 - y0, *a_NelLogo);
440 d->enableFog(fogEnabled);
441 d->activePixelProgram(NULL);
442 #else
444 Driver->drawQuad(CQuad(CVector(x0, y0, 0), CVector(x1, y0, 0), CVector(x1, y1, 0), CVector(x0, y1, 0)), CommandsMaterial);
446 #endif
448 // Set the text context
449 TextContext->setHotSpot (UTextContext::BottomLeft);
450 TextContext->setColor (CommandsFrontColor);
451 TextContext->setFontSize (CommandsFontSize);
453 // Display the user input line
454 ucstring line = ucstring("> ") + ucstring(CommandsListener.line()) + ucstring("_");
455 uint32 csi = TextContext->textPush(line);
456 float sw = TextContext->getStringInfo(csi).StringWidth / width; // make sure newly typed text is visible
457 TextContext->printAt(sw > CommandsBoxWidth ? CommandsBoxX - sw + CommandsBoxWidth : CommandsBoxX, CommandsBoxY, csi);
458 TextContext->erase(csi);
460 // Display stored lines
461 float yPos = CommandsBoxY;
462 list<string>::reverse_iterator rit = StoredLines.rbegin();
463 for (sint32 i = 0; i < CommandsNbLines; ++i)
465 yPos += CommandsLineHeight;
466 if (rit == StoredLines.rend()) break;
467 TextContext->printfAt(CommandsBoxX, yPos, (*rit).c_str());
468 rit++;
472 void clearCommands ()
474 StoredLines.clear ();
477 void releaseCommands()
479 #if SBCLIENT_DEV_PIXEL_PROGRAM
480 delete a_DevPixelProgram;
481 a_DevPixelProgram = NULL;
482 #endif
483 // Remove the displayers
484 CommandsLog.removeDisplayer(&CommandsDisplayer);
485 #ifndef NL_RELEASE
486 DebugLog->removeDisplayer(&CommandsDisplayer);
487 InfoLog->removeDisplayer(&CommandsDisplayer);
488 WarningLog->removeDisplayer(&CommandsDisplayer);
489 AssertLog->removeDisplayer(&CommandsDisplayer);
490 ErrorLog->removeDisplayer(&CommandsDisplayer);
491 #endif
493 // Remove callbacks for the config file
494 ConfigFile->setCallback("CommandsBoxX", NULL);
495 ConfigFile->setCallback("CommandsBoxY", NULL);
496 ConfigFile->setCallback("CommandsBoxWidth", NULL);
497 ConfigFile->setCallback("CommandsBoxBorder", NULL);
498 ConfigFile->setCallback("CommandsNbLines", NULL);
499 ConfigFile->setCallback("CommandsLineHeight", NULL);
500 ConfigFile->setCallback("CommandsBackColor", NULL);
501 ConfigFile->setCallback("CommandsFrontColor", NULL);
502 ConfigFile->setCallback("CommandsFontSize", NULL);
504 // Remove the keyboard listener from the server
505 Driver->EventServer.removeListener(EventCharId, &CommandsListener);
507 // Remove the material
508 Driver->deleteMaterial(CommandsMaterial);
511 NLMISC_COMMAND(clear,"clear the chat history","")
513 // check args, if there s not the right number of parameter, return bad
514 if(args.size() != 0) return false;
515 clearCommands ();
516 return true;
519 } /* namespace SBCLIENT */
521 /* end of file */