Freitag, 8. April 2016

Planet Rendeing : Recursive Level of Detail, With Code

Today I present you a level of detail algorithm for planet rendering. It has merely 100 lines of C++.

https://github.com/sp4cerat/Planet-LOD






Samstag, 19. März 2016

Basic Networking

Basic Networking working. So far without any physics & voxels. Running server + 4 clients @60fps on my Notebook simultaneously.


Donnerstag, 25. Februar 2016

OutStar Demo (Pre-Akpha)

This is a pre-alpha of OutStar - Enjoy.






It contains three modes:

1. The game mode (no shooting so far, just walk around)
2. Block edit (toggle with tab)
3. Sculpt editor (toggle with middle mouse button)

Controls:

F1 Screenshot
F2 Toggle Fullscreen
F3 Game/Edit Mode
F4 Sculpt Mode
F5 Save Level
F6 Load Level
F7..F10 Set Resolution 1024x512..1920x1080

TAB Toggle Edit/Game Mode

Space Jump
wsad Move Player
Shift Run

Game Mode:

LMB : Will be shoot

Edit Mode:
LMB set block
MMB Toggle Sculpting Tool
RMB delete block
Wheel: change block

Hold the LMB/RMB and drag to set a larger area

In sculpting tool:
Add block to octree : adds a new block to the available list


Dienstag, 3. November 2015

Game-Net: Simple RPC System for Games (C++11)

Summary
The library provides basic client / server network functionalities for games using RPCs. The major strength of the library is the template based RPC class. It allows to register and call RPCs effortless. It further includes a tutorial game server and game client (each around 300 lines of code ) for a very simple multiplayer shooting game as a proof of concept.
Network RPC Lib Features
  • Register RPCs in one line. The RPC class autodetects all paramters from the function pointer
  • RPC Data-type mismatch or wrong number of parameters are stated as error to ease debugging
  • Numbers are automatically sent as the smallest possible datatype (byte, short , .. )
  • Supports GLM datatypes for use in 3D Games
  • Supported Datatypes : (u)char,(u)short,(u)int,float,double,vector,map, GLM vec,mat and quat
  • Support for nested Datatypes like map [ string , vector ]
  • Reliable and unreliable calls possible
  • Function pointers of remote functions are not required
  • Based on ENet
  • Tested on Cygwin, Linux (Ubuntu) and Windows
  • C++11 based
Network RPC Lib Limitations
  • RPCs cannot be class member functions
  • No compression
  • No encryption
  • Only void functions supported. Non-void functions were tested but complicated everything.
  • Client to Client connections are not supported
Example Game Features
  • Lobby
  • Multiple Games
  • Handle spwaning/removing of game objects
  • Simple Shooting functionality
  • Intentionally textmode for simplicity
Benchmark
A first simple test on localhost (Core i7 Notebook) gave:
1 Call / Network Update:
  • 69.000 unreliable RPC calls/sec [client.call_ex(0,"hello_server", "Greetings")]
  • 74.000 reliable RPC calls/sec [client.call_ex(1,"hello_server", "Greetings")]
10 Calls grouped / Network Update
  • 144.000 unreliable RPC calls/sec [client.call_ex(0,"hello_server", "Greetings")]
  • 310.000 reliable RPC calls/sec [client.call_ex(1,"hello_server", "Greetings")]
20 Calls grouped / Network Update
  • 142.000 unreliable RPC calls/sec [client.call_ex(0,"hello_server", "Greetings")]
  • 364.000 reliable RPC calls/sec [client.call_ex(1,"hello_server", "Greetings")]
Note that this is not about the response time
Example Usage
Call Server Function:
Client Side:
NetClient client;

void set_pos(vec3 pos)
{
    // do something
    exit(0);
}

int main()
{
    rpc_register_remote(client.get_rpc(), login);
    rpc_register_local(client.get_rpc(), set_pos);
    client.connect("localhost", 12345);
    client.call("login", "myname", "pass");
    while(1) client.process();
    //client.disconnect();
}
Server Side:
NetServer server;

void login(uint clientid, string name, string password)
{
    // clientid is the first parameter for server functions
    server.call(clientid, "set_pos", vec3(1,2,3));    
}

int main()
{
    rpc_register_local(server.get_rpc(), login);
    rpc_register_remote(server.get_rpc(), set_pos);    
    server.start();
    core_sleep(10000) ; // wait client to do stuff
    server.stop();
}

Dienstag, 28. Juli 2015

Github Code

I shifted some of my code to GITHUB. You can find it here https://github.com/sp4cerat

Mittwoch, 15. Juli 2015

OpenGL Game GUI / Widgets with Source Code (C++)

The GUI is intended for PC and/or Console Games. 
Focus was mostly on keeping everything simple, easy to use, fast, and flexible (like having skin and ttf support).
The performance is ~700 fps for 20 windows and 100 fps for 100 windows on a Notebook PC (NVidia GTX 765 / Core i7 2.4). 

The source (MIT license) can be downloaded from GitHUB or here



Usage examples:

Creating and opening a window: 

gui.window["mywin"]=Gui::Window("Hello World",100,100,350,250);

Adding a button:

gui.window["mywin"].button["Ok1"]=Gui::Button("OK",20,100,60,20);

Adding a callback to close the window when pushing the button:

gui.window["mywin"].button["Ok1"].callback_pressed=
  [](Gui::Window *w,Gui::Button* b,int index) { w->close(); };


Here two screenshots with different skins
( VS2012 / OpenGL / GLUT based / MIT license )

Features:
  • Advanced skin scaling: define how the inner and borders of a texture shall be scaled ( simple scale, repeating inner pattern or constant outer frame, carried out by 3 Shader types)
  • UTF8 Support
  • TTF Support
  • Easy skinning support
  • Alpha support (RGBA), so you can have transparent windows/widgets etc
  • direct access to all controls and their members
  • Non-blocking visualization
  • Callback support
  • Different from most GUIs, Widgets are stored directly inside the GUI rather having local variables pointing to instances of an overwritten class.
  • Directory: Controls are stored and accessed by a tree structure that is rendered every time like a scene graph
  • No event loop, show function or update function
  • No need to have a timer that calls an update function
  • Lightweight: Only Depends on GL and libFreetype and DevIL
  • Can easily be used in SDL, Qt and other environments. Just plug in the keyboard and mouse events and call the gui's draw function from your main render loop.
  • Config file support for default variables (font,padding etc) and skin textures+scaling parameters
  • Only 2000 lines of code for the entire Gui class including all widgets. Therefore easy to modify and extend.
  • Comes with a simple file-browser (See screenshot1)
  • MIT license
  • Multi-screen support (same as multiple Desktops). You can have a title screen, loading screen, ingame screen etc. Simply create them at the beginning and the switch between by setting gui.active_screen=number;
  • Window manager
  • Context menu
  • Custom mouse pointer
  • Controls have support for custom user variables like control.var.string["myvar"]="hello"
Available classes for controls:
  • Window class
  • Label class
  • Button class
  • Combo class
  • Radio class
  • Tab class
  • Textedit class
  • Slider class
  • CheckBox class
  • Menu class
What the GUI is good for:
  • PC/Console Games
  • Simple menus
What the GUI might not be suited for
  • Complex GUIs that need tree-views , docking ,drag & drop etc
  • Mobile Devices ; perhaps too slow (needs testing) and also the render code needs to become OpenGL ES
Current Limitations (might be solved in the future)
  • Uses old OpenGL (glMatrix etc)
  • Usually one or two render calls per widget rather than one opengl render call for the entire gui.
  • 2D windows/widgets only. You could overwrite the render shader to get 3D, but you would have to map 2D mouse coordinates to 3D then by yourself. 
  • No animations (you could create them yourself by updating the textures accordingly or modifying the shader that render the widgets)
  • Only one font size and one font type
  • The GUI class is a singleton
  • The TextEdit does not support arbitrary cursor position or ctrl+c/v/x operations
  • Drag and Drop is not supported
  • No automatic window layout
  • No docking
  • No Ressource files (yet)
  • No treeview class
  • No caching of rendered labels, geometry, etc. Therefore every frame, the entire tree is traversed and every single character of a rendered text is processed for rendering.
The usage is also described in the previous post.

The code used to create window + widgets + menu in screenshot2  is the following:

 gui.init( Gui::Flags::CONTEXT_MENU | Gui::Flags::CUSTOM_MOUSE ,
    "../data/gui_global.txt" , 
    "../data/gui_skin.txt");

 // Main Window

 Gui::Window w=Gui::Window("Hello World",100,100,350,250); 

 // Add Simple Label to Window

 w.label["l"]=Gui::Label("Label",20,70,100,20);

 // Add Simple Button to Window

 w.button["Ok1"]=Gui::Button("OK",20,100,60,20);
 w.button["Ok1"].callback_pressed=
  [](Gui::Window *window,Gui::Button* control,int index)
  {
   window->close();
  };

 w.button["Ok2"]=Gui::Button("",220,100,100,100);
 w.button["Ok2"].skin=Skin( "../data/smiley.png",
        "../data/smileybw.png",
        "../data/smiley2.png");

 // Add Simple Combo to Window

 w.combo ["cb"]=Gui::Combo(120,100,60,20);
 w.combo ["cb"].add_item("test");
 w.combo ["cb"].add_item(L"東京");
 w.combo ["cb"].callback_selected=
  [](Gui::Window *w,Gui::Button* control,int index) // text entered callback example
  {
   Gui::Combo &c=*(Gui::Combo*)control;
   w->label["l"].text=Gui::String( c.selected ) + "  selected";
   w->label["l"].textcolor=vec4f(1,0,0,1);
  };

 // Add Text Edit to Window

 w.textedit["txt"]=Gui::TextEdit(10,"text",20,150,160,20);
 w.textedit["txt"].callback_text_entered=  
  [](Gui::Window *w,Gui::Button* control,int index) // text entered callback example
  {
   Gui::TextEdit &t=*(Gui::TextEdit*)control;
   w->title.text=t.text;
  };

 // Add Radio

 w.radio["rad"]=Gui::Radio(20,190,20,20); // first button
 w.radio["rad"].add_item(50,190);   // second button
 w.radio["rad"].add_item(80,190);   // third button
 w.radio["rad"].callback_pressed=
  [](Gui::Window *w,Gui::Button* control,int index)
  { 
   w->x+=10;
  };

 // Add Slider

 w.slider["s1"]=Gui::Slider( 0,200,100,   /* min,max,default*/ 
        20,220,160,20); /* window x,y,sx,sy */ 
 w.slider["s1"].callback_pressed=
 [](Gui::Window *w,Gui::Button* control,int index)
 {
  Gui::Slider &b=*((Gui::Slider*) control); 
  w->button["Ok1"].text=Gui::String(int(b.val)); 
 };

 w.slider["s2"]=Gui::Slider( 0,200,100,   /* min,max,default*/ 
        350,100,20,160, /* window x,y,sx,sy */
        Gui::Slider::VERTICAL );

 // Add File Menu to Window

 Gui::Menu m=Gui::Menu("File",/* x,y,sx,sy */ 9,39,50,20, /* menuwidth */ 100);
 m.add_item("Load",
  [](Gui::Window *window,Gui::Button* control,int index) // menu button callback
  {
   gui.screen[0].window["filebrowser"]=  // open file dialog
    gui_file_dialog( "Load SaveGame" , "Load" , "Cancel" ,
     /*get_current_dir()*/ "..\\data\\win8",".png", 100,100,

     // file dialog ok button callback
     [](Gui::Window *w,Gui::Button* b,int index) 
     {  
      MessageBoxA(0, 
       w->textedit["Filename"].text.c_str() , 
       w->label["dir"].text.c_str() ,0);  
      w->close();    
     }
   );
  });

 m.add_item("Close",
  [](Gui::Window *w,Gui::Button* control,int index) // menu button callback
  {
   w->parent->close(); // close window
  });

 m.add_menu("submenu");
 m.window.menu[0].add_item("test1");
 m.window.menu[0].add_item("test2");

 w.menu["menu"]=m;

 // Add new Window to Screen 0 (default)

 gui.screen[0].window["hello1"]=w; // finally put window on the screen (1st copy)

 // Modify and Add new Window to Screen 0 (default)

 w.move(500,100);
 w.resize(400,300);
 w.minsize(150,150);

 gui.screen[0].window["hello2"]=w; // finally put window on the screen (2nd copy)

 // -------------------------------------------------------------------------

 // also use our previous menu as context menu and file menu
 // Note : "context_menu" is reserved for the context menu
 //    all other id names are common menus on the background

 gui.screen[0].menu["context_menu"]=m;

 gui.screen[0].menu["file"]=m;
 gui.screen[0].menu["file"].y=5;

 // -------------------------------------------------------------------------

 // Add Button to Background

 gui.dialog["sample"]=w; // store for later use in the callback

 gui.screen[0].button["more"]=Gui::Button("More Windows Plz!!",50,50,200,20);
 gui.screen[0].button["more"].callback_pressed=
  [](Gui::Window *w,Gui::Button* control,int index) // menu button callback
  {
   int id=gui.screen[0].window.add(gui.dialog["sample"]);
   gui.screen[0].window[id].x= timeGetTime() % (int)gui.screen_resolution_x;
   gui.screen[0].window[id].y= timeGetTime() % (int)gui.screen_resolution_y;
  };

 // Add Tabbed Window to Background

 Gui::Tab t=Gui::Tab("Win1",350,150,300,200,50,20);;
 t.add_tab("Win2");
 t.add_tab("Win3");
 t.add_tab("Win4");
 loopi(0,4)
 {
  t.window[i].button.add(Gui::Button("OK",20+i*10,20,60));
  t.window[i].label["lab"] =Gui::Label("some text",20+i*20,90,100);
  t.window[i].button["test2"]=Gui::Button("OK",100+i*10,20,60);
  t.window[i].button["test3"]=Gui::Button("OK",50+i*10,50,60);
 }
 t.flags=Gui::Tab::MOVABLE; // Make it movable
 gui.screen[0].tab["mytab"]=t;



Main reason for the development of the GUI was, that after trying several gui's more or less suited for games (LibRocket, Qt, NVWidgets, CEgui, etc), I found that none of them was really light weight, easy to use and fully skinable at the same time. So the solution was to create one which is exactly so. 




Mittwoch, 1. Juli 2015

OpenGL Game GUI & Widget Development (Alpha Demo)

Today I am going to share some progress on my GUI project.

The Design Goals were:
  • Simplicity : Create a control in one line
  • Easy Skinning support
  • TTF and UTF8 support
  • Directory : Controls can be accessed by a tree structure
  • Direct access of all data members like if a button is pressed e.g.
  • No Event Loop
  • Static non-blocking visualization
  • Dialog Templates from ressource text file
  • Callback support 

Some simple examples:
Creating a window: gui.window["idname"]=Gui::Window("Title",100,100,250,350);
Closing a window: gui.window.erase("idname");
Adding a button : gui.window["idname"].button["load"]=Gui::Button("Load",20,20,50,30);

Change the skin of a window or other control:
gui.window["idname"].skin=Skin("normal.png","hover.png","selected.png");

There is no need to create a variable for most cases. The GUI handles that for you. It will cover basic functions that a required in a game. Its not optimized for speed, yet fast enough in most cases.

You can fetch an alpha demo of the gui here : [ DOWNLOAD ]

I will post more details soon.