Jump to content

And, Hello

Paul Thomas


There are several here who already know me, but for those who don't, my name is Paul Thomas. I've been programming for a long time now; I started when I was 16 (I'm now 30) with HTML, CSS, Javascript, and CGI/Perl. Hell back then there wasn't a lot of people who even used the internet at home, lol. At least in my area, I'm sure others, especially in California, were a lot further ahead at that time in terms of technology and the interest in the technology.


Through the years I've learned multiple languages from strictly web-based to software based. My interest in computers when I was 16 was to make a game, but at the time I thought it would have been much easier to prototype the whole idea in a web-based browser game. I had completed the browser game, which was the original "Eternal Crisis," and worked nicely. My plan was to update the entire web-based system, polish everything, and officially advertise (I had invited friends to play the game). That's when I learned about a "fried hard drive" and eventually learned about "backup" and how to install a hard drive.


Those whom already know me, know what Eternal Crisis is, and my Blogger shows some of the history on that project. I had taken that project, along with another, over to Unreal Engine 3 because it best suit the project. Along the years of learning that engine I was using LE for prototyping ideas and so forth.


While I'm not working on my own engine (temporarily titled "3D Dice"), FPS/RPG framework for UE3, or R.A.T.S., I work on my framework for Leadwerks Engine 2.5. I've never shared this framework before, in fact it always felt like I had to pull it out of a shallow grave each time I added to the framework design and programming. I'm a notebook junkie, I plan out mechanics, structures, and so forth on paper, before going over to digital. Old habbits that die hard I guess.


Now I felt like sharing the progress, which isn't a lot, but it's a great start to me. It's a great start to me because it actually runs, lol. The state of the framework isn't even close to the final planned and written design, but progress is progress. Always move forward until it's finished, even if you can only pick that project up once every two weeks (by then I/you should probably take a look at your workload and fix it instead of attempting such project schedules; however this isn't vital to me and rates low on my importance scale), if it's updated then progress is moving forward. This is also harder to work with if you don't plan your software before actually programming (unless it's routine for you with available libraries for shortcuts in development).


As most programmers should know, the programmers "update" isn't as glamorous as an artists "update" as it's not about visual stimulation but overall program/software flow. In the case of my LE framework (obviously untitled) it's all about providing mechanics and how that is achieved is important especially in the case of LUA access and how everything works together; from configuration/data management, to input binding, and all the way down to AI.


Until occupied again by my other tasks I will eventually share the entire framework structure and I will always be showing examples of syntax; cause that's what programmers do. Just to clear the obvious questions that may come from the community:


Q) Do I plan to give away code, the framework, and be an open source kind of person?

A) No, not really. First of all, you would have to wait, to anyone else at the moment the framework is as useful is a partially finished library. How long you would have to wait would depend on how much time I can spend on the framework and in all honestly it's not much at all (read above, and actually read).


Q) Do I plan to sell or lease the framework?

A) No, don't think so. I even think that's against Leadwerks terms since it could be deemed an "FPS Creator," which is definitely in the terms.


Q) Is my framework really that great?

A) Nah, I mostly ramble, and I'm actually writing this to share with long time friends here at Leadwerks. Some won't even visit anywhere else to communicate because they are so used to using Leadwerks for that; it is indeed where we all met.


Q) Who are my friends?

A) I have none, it was a lie.




Now, about this framework. This "framework" isn't the same, exactly, as the framework that comes with LE. The framework that comes with LE handles some dirty work for you when it comes to creating the worlds, cameras for those worlds, shader effects, and helper functions. The framework I'm designing is technically similar to a game engine. I personally consider Leadwerks Engine as a rendering API with physics and this framework uses that rendering API and provides mechanics. The mechanics the framework provides is what makes up the detail of the framework.








The above are considered "managers" in that they only handle what they should be managing. The "INI" only works with INI files, such as a configuration manager. The "SQL" only works with SQLite3, providing helper functions for easier SQL management, and so forth. There are more planned managers than the above, but these are what are completed in terms of programming. The only real interesting portion to discuss about the framework is within the "Game" manager itself.


The game manager provides two special classes/managers; "Object" and "Actor." Actor inherits everything about an Object. What defines an Object is a game entity that is never interacted with by the player. Objects are useful as it can be used for multiple purposes without consuming a lot of resources for each "component" or "plugin" I'd like to add onto the framework. For example, a Timer would be an Object. You don't interact with a Timer in a game, but there is a timer running in the background.



class ETimer : public EObject
   virtual ~ETimer(void);

   void Initialize(void);
   void SetTimer(float StartTime);
   void StopTimer();


While working with the framework you would do something similar to:

// EGame::EObject
// EGame::Objects
EObject Objects;
// ..
ETimer Timer;
Objects.Add("Timer", Timer);
// ..

ETimer Timer = Objects.Get("Timer");
// ..
// inherited by EObject


An Actor inherits everything that defines an Object. The difference between the two is that an Actor is something that a player could see, hear, interact with, or can move, rotate, and so forth. If you can see how this is all going, everything starts extending the Actor, such as the character, weapon, or items. Here are some examples of working with Actors in the framework:


// EGame::Actors
Actors.Add("oilbarrel", "oilbarrel.gmf");
// ..
Actors.Rotate("oilbarrel", vec3(10.0f, 0.0f, 10.0f));
// ..
Actors.Translate("oilbarrel", vec3(10.0f, 0.0f, 0.0f));
// ..
EActor barrel = Actors.Get("oilbarrel");
// rotate with interpolation
barrel.Rotate(vec3(1.0f), 0.1f);
barrel.Translate(vec3(0.0f, 1.0f, 0.0f), 0.1f);
// ..
EActor Barrel;
// new name
Barrel.Name = "barrel01";
// new mesh
Actors.Edit("oilbarrel", Barrel);


A quick overview of an Actor:



Each Actor can also have children which are also Actors. This provides another version of parent/child relationships but also provides additional benefits which will be discussed in later blogs. The ID and Name variables are provided by Object and the Object provides more variables, but is listed for importance.


When creating an Actor it is automatically tagged for unique identification. In the above example "oilbarrel" is actually stored as "oilbarrel_0" and simply incremented for each Actor that is created. This is identified by the Actors "Tag". The "Name" variable is a forced name, therefore searching for an Actor by the name, with more than one Actor having the same name, the first result is returned.


Actors will be automatically created properly for each entity in a scene. The framework will be using a custom scene manager and handles initial Actor creation. Programmers/Scripters can then add to the Actors list with C++ or LUA like the above examples.


class MyGame : public EGame
   void Load(void);
   void Update(float DeltaTime);
   // ..
   void MyGame::Load(void)
  Actors.Add("custom_actor", "mymesh.gmf", "force_tag_name");

  EActor actor = Actors.Get("custom_actor");
  EActor actorCopy = Actors.GetTag("force_tag_name");


   void MyGame::Update(float DeltaTime)
  EActor actor = Actors.Get("custom_actor");
  // interp move with speed and threshold option
  actor.Move(vec3(10.0f), 1.0f, 1.0f, 0.35f);


In upcoming blogs, when I do get the time, I'll post up some videos. Those selected for the invite only alpha testing will get their information on how to use the framework. Friends of mine that didn't get an invite and are interested in alpha testing please private message me; I most likely didn't send you the information because I figured you were busy with your own project(s).


Well, out of time. Thanks for reading.


Recommended Comments

Sorry ... but who are you?



Paul's been around a long time, he just has a fancy new avatar.

Awesome, it's now fancy. The last time I made a new avatar you said it was emo. I guess this is an improvement. Granted, I stole the overall style from Assassin's Creed. I can't help it, fantastic storyline, awesome era, great art, beautiful mechanics and AI.

Share this comment

Link to comment

Blog Update:

I've been spending time organizing the classes, preparing to share with LUA, and DLL. Figured now while it's early. It may be too early to provide much to LUA or DLL. In any case, soon it's time to move on to actual actors (camera, terrain, volumes/triggers, etc.), after I finish with meshes.

Share this comment

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Blog Entries

    • By jen in jen's Blog 4
      I've got a bit of free time on my hands for a while. I plan to take up Leadwerks again and come up with a simple project to have fun with.
      I use VSCode at work and I don't have a Windows machine at the moment. Codeblocks is a bit dated now and I'm not sure if it has all the features to fit my workflow so I can't use it. 
      It's a bit fiddly to build C++ apps on VSCode. There's a prescribed method of setting up your C++ project in the official hubs but I don't think those are necessary in my case, I just need a script that builds the project which I have below.
      By the way, VSCode website is here: https://code.visualstudio.com/
      Have fun.
      Save as build.sh in your project's root folder and run using build.sh or build.sh -r for release. Works for Stable version LW and any previous versions(?) - at least v4.5 (archived). BETA branch (4.6?) doesn't seem to build for me, missing Leadwerks.a file.
      Disclaimer: not really fully tested for bigger projects? I've only tested this with sample projects that have no additional project folder structure in its Source so I'm not sure if the script will propagate its search for CPP files thoroughly and process each file successfully in bigger projects. Back-up project files before running the script for the first time please.
      Updated: 26/02/2020
      #!/bin/sh if [ $1 == "-h" ]; then echo "Build script is set to DEBUG by default. Set -r in first argument of the script to build for release."; exit 1; fi if [ $1 != "" ] && [ $1 != "-r" ] && [ $1 != "-h" ]; then echo "Type build.sh -h to see brief help description."; exit 1; fi debugFlags='-g -DDEBUG -D_DEBUG'; debugLibPath='Debug'; PROJECT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) LEADWERKS_PATH=~/.local/share/Steam/steamapps/common/Leadwerks declare a compiledFiles; declare a includedFilePaths; if [ $1 == "-r" ]; then debugFlags=''; debugLibPath='Release'; fi truncate -s 0 $PROJECT_PATH/build.log echo "Leadwerks Path: $LEADWERKS_PATH" echo "Project Path: $PROJECT_PATH" echo "Compiling source..." if [ ! -d "$PROJECT_PATH/Compilations" ]; then mkdir $PROJECT_PATH/Compilations; fi if [ ! -d "$PROJECT_PATH/Compilations/$debugLibPath" ]; then mkdir $PROJECT_PATH/Compilations/$debugLibPath; fi for f in $(find $PROJECT_PATH/Source -name '*.h' ); do includedFilePaths+=("-I $(dirname "${f}")") done includedFilesJoined=$(printf "%s " "${includedFilePaths[@]}") includedFilesJoined="-${includedFilesJoined:1}" for f in $(find $PROJECT_PATH/Source -name '*.cpp' ); do originalSourcePath=$PROJECT_PATH/Source; compilationsPath=$PROJECT_PATH/Compilations/$debugLibPath; compiledFilePath=${f/.cpp/'.o'}; compiledFilePath=${compiledFilePath/$originalSourcePath/$compilationsPath}; mkdir -p $(dirname "${compiledFilePath}") g++ -std=c++0x $debugFlags -w -fexceptions -msse3 -DDG_DISABLE_ASSERT -DZLIB \ -DPLATFORM_LINUX -D_NEWTON_STATIC_LIB -DFT2_BUILD_LIBRARY -DOPENGL \ -Dunix -D__STEAM__ -D_POSIX_VER -D_POSIX_VER_64 -DDG_THREAD_EMULATION \ -D_STATICLIB -DDG_USE_THREAD_EMULATION -DGL_GLEXT_PROTOTYPES -DLEADWERKS_3_1 \ -DLUA_USE_LINUX -D_GLIBCXX_USE_CXX11_ABI=1 -D_CUSTOM_JOINTS_STATIC_LIB -fPIC -O2 -std=c++0x \ $includedFilesJoined \ -I $LEADWERKS_PATH/Include/Libraries/VHACD/src/VHACD_Lib/inc \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/sdk/dMath \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/sdk/dgNewton \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/sdk/dContainers \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/sdk/dgCore \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/sdk/dgTimeTracker \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/sdk/dgPhysics \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/sdk/dCustomJoints \ -I $LEADWERKS_PATH/Include/Libraries/tolua++-1.0.93/include \ -I $LEADWERKS_PATH/Include/Libraries/lua-5.1.4 \ -I $LEADWERKS_PATH/Include/Libraries/freetype-2.4.7/include \ -I $LEADWERKS_PATH/Include/Libraries/enet-1.3.1/include \ -I $LEADWERKS_PATH/Include/Libraries/RecastNavigation/DebugUtils/Include \ -I $LEADWERKS_PATH/Include/Libraries/RecastNavigation/Detour/Include \ -I $LEADWERKS_PATH/Include/Libraries/RecastNavigation/DetourCrowd/Include \ -I $LEADWERKS_PATH/Include/Libraries/RecastNavigation/DetourTileCache/Include \ -I $LEADWERKS_PATH/Include/Libraries/RecastNavigation/Recast/Include \ -I $LEADWERKS_PATH/Include/Libraries/libvorbis/include \ -I $LEADWERKS_PATH/Include/Libraries/NewtonDynamics/packages/thirdParty/timeTracker \ -I $LEADWERKS_PATH/Include/Libraries/libvorbis/lib \ -I $LEADWERKS_PATH/Include/Libraries/libogg/include \ -I $LEADWERKS_PATH/Include \ -I $LEADWERKS_PATH/Include/Libraries/zlib-1.2.5 \ -I $LEADWERKS_PATH/Include/Libraries/zlib-1.2.5/contrib/minizip \ -I $LEADWERKS_PATH/Include/Libraries/freetype-2.4.7/include/freetype \ -I $LEADWERKS_PATH/Include/Libraries/freetype-2.4.7/include/freetype/config \ -I $LEADWERKS_PATH/Include/Libraries/LuaJIT/dynasm \ -I $LEADWERKS_PATH/Include/Libraries/glew-1.6.0/include \ -c $f -o $compiledFilePath; compiledFiles+=($compiledFilePath) done compiledFilesJoined=$(printf "%s " "${compiledFiles[@]}") compiledFilesJoined="/${compiledFilesJoined:1}" echo "Building project..."; g++ -o $PROJECT_PATH/${PWD##*/} $compiledFilesJoined -s "$LEADWERKS_PATH/Library/Linux/$debugLibPath/Leadwerks.a" -ldl \ -lopenal -lGL -lGLU "$LEADWERKS_PATH/Library/Linux/libluajit.a" $PROJECT_PATH/libsteam_api.so \ -lX11 -lXext -lXrender -lXft -lpthread -lcurl "$LEADWERKS_PATH/Library/Linux/libopenvr_api.so" echo "Build complete. See build.log for result summary." About the game: I'm kind of disappointed with the Action RPGs released recently. I want to give the genre a shot, present my own interpretation of how it should look like? Dark, medieval, less electric, modest if not rare use of glow shaders... maybe?

    • By Josh in Josh's Dev Blog 0
      A new update is available for beta testers. This adds a new LOD system to the terrain system, fixes the terrain normals, and adds some new features. The terrain example has been updated ans shows how to apply multiple material layers and save the data.

      Terrain in LE4 uses a system of tiles. The tiles are rendered at a different resolution based on distance. This works great for medium sized terrains, but problems arise when we have very large view distances. This is why it is okay to use a 4096x4096 terrain in LE4, but your camera range should only show a portion of the terrain at once. A terrain that size will use 1024 separate tiles, and having them all onscreen at once can cause slowdown just because of the number of objects. That have to be culled and drawn.

      Another approach is to progressively divide the terrain up into quadrants starting from the top and working down to the lowest level. When a box is created that is a certain distance from the camera, the algorithm stops subdividing it and draws a tile. The same resolution tile is drawn over and over, but it is stretched to cover different sized areas.

      This approach is much better suited to cover very large areas. At the furthest distance, the entire terrain will be drawn with just one single 32x32 patch. Here it is in action with a 2048x2048 terrain, the same size as The Zone:
      This example shows how to load a heightmap, add some layers to it, and save the data, or load the data we previously saved:
      --Create terrain local terrain = CreateTerrain(world,2048,32) terrain:SetScale(1,150,1) --Load heightmap terrain:LoadHeightmap("Terrain/2048/2048.r16", VK_FORMAT_R16_UNORM) --Add base layer local mtl = LoadMaterial("Materials/Dirt/dirt01.mat") local layerID = terrain:AddLayer(mtl) --Add rock layer mtl = LoadMaterial("Materials/Rough-rockface1.json") rockLayerID = terrain:AddLayer(mtl) terrain:SetLayerSlopeConstraints(rockLayerID, 35, 90, 25) --Add snow layer mtl = LoadMaterial("Materials/Snow/snow01.mat") snowLayerID = terrain:AddLayer(mtl) terrain:SetLayerHeightConstraints(snowLayerID, 50, 1000, 8) terrain:SetLayerSlopeConstraints(snowLayerID, 0, 35, 10) --Normals if FileType("Terrain/2048/2048_N.raw") == 0 then terrain:UpdateNormals() terrain:SaveNormals("Terrain/2048/2048_N.raw") else terrain:LoadNormals("Terrain/2048/2048_N.raw") end --Layers if FileType("Terrain/2048/2048_L.raw") == 0 or FileType("Terrain/2048/2048_A.raw") == 0 then terrain:SetLayer(rockLayerID, 1) terrain:SetLayer(snowLayerID, 1) terrain:SaveLayers(WriteFile("Terrain/2048/2048_L.raw")) terrain:SaveAlpha(WriteFile("Terrain/2048/2048_A.raw")) else terrain:LoadLayers("Terrain/2048/2048_L.raw") terrain:LoadAlpha("Terrain/2048/2048_A.raw") end The x86 build configurations have also been removed from the game template project. This is available now in the beta tester forum.
    • By Josh in Josh's Dev Blog 2
      Documentation in Leadwerks 5 will start in the header files, where functions descriptions are being added directly like this:
      /// <summary> /// Sets the height of one terrain point. /// </summary> /// <param name="x">Horizontal position of the point to modify.</param> /// <param name="y">Vertical position of the point to modify.</param> /// <param name="height">Height to set, in the range -1.0 to +1.0.</param> virtual void SetHeight(const int x, const int y, const float height); This will make function descriptions appear automatically in Visual Studio, to help you write code faster and more easily:

      Visual Studio can also generate an XML file containing all of the project's function descriptions as part of the build process. The generated XML file will serve as the basis for the online documentation and Visual Studio Code extension for Lua. This is how I see it working:

      I am also moving all things private to private members. I found a cool trick that allows me to create read-only members. In the example below, you can access the "position" member to get an entity's local position, but you cannot modify it without using the SetPosition() method. This is important because modifying values often involves updating lots of things in the engine under the hood and syncing data with other threads. This also means that any method Visual Studio displays as you are typing is okay to use, and there won't be any undocumented / use-at-your-own risk types of commands like we had in Leadwerks 4.
      class Entity { private: Vec3 m_position; public: const Vec3& position; }; Entity::Entity() : position(m_position) {} It is even possible to make constructors private so that the programmer has to use the correct CreateTerrain() or whatever command, instead of trying to construct a new instance of the class, with unpredictable results. Interestingly, the constructor itself has to be added as a friend function for this to work.
      class Terrein { private: Terrain(); public: friend shared_ptr<World> CreateTerrain(shared_ptr<World>, int, int, int) }; The only difference is that inside the CreateTerrain function I have to do this:
      auto terrain = shared_ptr<Terrain>(new Terrain); instead of this, because make_shared() doesn't have access to the Terrain constructor. (If it did, you would be able to create a shared pointer to a new terrain, so we don't want that!)
      auto terrain = make_shared<Terrain>(); I have big expectations for Leadwerks 5, so it makes sense to pay a lot of attention to the coding experience you will have while using this. I hope you like it!
  • Create New...