What is OpenGL Scripting?
Like injection, reflection, and color, OpenGL scripting is yet another alternative method of creating RS3 macro programs. After reading this tutorial, you will be able to create powerful and flawless scripts, capable of complex tasks usually discarded as too difficult for color only. Pending an ogLib update to support SRL-6, You will also learn how to incorporate both color and OpenGL methods into your scripts, combining the two scripting approaches to get the best of both worlds.
Without going into unnecessary detail, OpenGL allows us to examine the information being sent to your computer's graphics card, giving information on models, textures, chars, and more. We can script in resizable mode, easily interact with environments regardless of camera angle, and even get perfectly accurate player minimap and 3D world locations. It is not without its flaws, however, when used correctly and cleverly, OpenGL can accomplish some awesome things!
It is highly recommended to first familiarize yourself with SRL-6 scripting before learning OpenGL, as the combined information will give you many more creative options. This tutorial assumes basic understanding of Lape and beginner SRL-6 scripting concepts. If you have any questions, feel free to post.
Table of Contents
Part 1 :: Setting up OpenGL
OpenGL scripting and program execution requires some modified dynamic link libraries (.DLLs) for RS3 and Simba to use. Additionally, we use a different set of includes (
ogLib) to develop OpenGL scripts. This library currently supports RS3 - EoC only.
Automatic Installation
Download
ProSocks.dll and place it into
Simba\Plugins\
Download
Attachment 27083 and place it into
Simba\Scripts\. Open and run the script.
Manual Installation
Download the
OpenGL32.dll and
GLX.dll plugins, developed by @
Brandon, here:
GLX v3.7
Download the
ogLib includes, a library designed and developed by @
Clarity and @
Obscurity, here:
ogLib v1.0a
Note that ogLib is an ongoing project, and contributions are welcomed! Some elements have yet to be added, such as in-depth mouse movement and SRL-6 compatibility. We are tackling the priority elements first, such as interfaces, mapping, and combat.
Once you have extracted the contents, copy
OpenGL32.dll and
GLX.dll into your
C:\...\Simba\Plugins\ directory. Next, copy the
ogLib\ folder into your
C:\...\Simba\Includes\ directory. It's that simple!
Part 2 :: OpenGL Data Types
Before we go any further, you've got to know the basics of OpenGL and the various data types. Unique to OpenGL, these types are:
- glChar / glCharArray - {TEXTUREID = 0, COLOUR = 0, X = 0, Y = 0, LETTER = , SHADOW = False, TRANSLATE = [0, 0, 0], BOUNDS = {X1 = 0, Y1 = 0, X2 = 0, Y2 = 0}}
Description: Each and every character on screen, be it a letter, number, or special character, may be viewed as a glChar. The glChar record contains vital information regarding each character; Things like color, font, and location on screen.
Record:
- TextureID:
Think of a character's texture ID as its font. Much like Comic Sans MS, for example, a right click menu typically uses the fonts 17 and 91. - Colour:
This property simply contains the colour of the character. The orange colour from hovering over a chat option, for example, is 37083. - X / Y:
The position at which a character can be found on screen can be viewed in its X and Y properties. This coordinate is to the center-point of the character. - Letter:
This is likely the most important property of a glChar. Letter contains the character which was found. This will always be a single character and could consist of any alphanumeric or special character. - Shadow:
The shadow property, which is very rarely true, is quite simply whether or not the text contains a shadow. Although some text appears to have a shadow, it may not. Take the following image for example:

Surely each one of those characters has a black shadow? This is incorrect. While they appear to have shadows, it's simply a 200 drawn ontop of a slightly offset, black 200. Therefore, the total number of characters in the image is 6. - Bounds:
The bounds of a glChar simply contain the coordinates of each corner. Calculating the center-point of them would result in the glChar's X / Y, as mentioned earlier.
- glModel / glModelArray - {ID = 0, TID = 0, X = 0, Y = 0}
Description: For the most part, it's fairly safe to assume that any 3D object or any item that appears in the 3D plane of RuneScape is a glModel; From players, to monsters, to target reticles, to the animated flag shown on screen while waiting for a Pest Control game to start. They're all models.
Record:
- ID:
Each model in RuneScape has an ID. These typically tend to remain constant. For example, it's fairly safe to assume that if you check and see that a Rorarius has an ID of 3227299924, it'll always have that ID. - TID:
A model's triangle count. Essentially, it should "technically" be "almost" as accurate as the ID. - X / Y:
The position at which a model can be found on screen can be viewed in its X and Y properties. Keep in mind that if drawn on the 3D plane, the model's X and Y will be located at the base of the model. Take the following image for example:

In this case, the model's X and Y is positioned at the base of the player near the feet.
- glTexture / glTextureArray - {ID = 0, ColourID = 0, FullColourID = 0, X = 0, Y = 0, BOUNDS = {X1 = 0, Y1 = 0, X2 = 0, Y2 = 0}}
Description: Almost everything that seems 2D in RuneScape can be retrieved as a glTexture. These are most often used for buttons, icons, interfaces, inventory items, equipped items, abilities, and anything in-between.
Record:
- ID:
glTextures, like glModels, always have an ID. However, this ID is rarely unique, making relying on solely this property for locating items and objects unreliable. For example, different potion flasks, summoning pouches, runes, tend to share a texture ID. Take the following GIF for example:

Here we can see that a Super restore (6) shares a texture ID with an Overload flask (1). - ColourID:
As mentioned before, textures can share a TextureID. To distinguish between these textures, we often use the ColourID. For now, lets just call it a summary of all colours within the texture. - X / Y:
The position at which a texture can be found on screen can be viewed in its X and Y properties. This is coordinate is the center-point of the texture. - Bounds:
The bounds of a glTexture simply contain the coordinates of each corner. Calculating the center-point of them would result in the glTexture's X / Y, as mentioned earlier.
Part 3 :: Spawning and Saving SMART with ogLib
Before we do anything requiring OpenGL, you need to spawn a SMART client with the OpenGL plugin. To do this, you have to setup ogLib using
ogl.setup(). See the sample
Script 3.1 below:
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
end.
ogl.setup() requires two sets of parameters. The first set, consisting of two integers, sets the dimensions of the client. The second set, consisting of four integers, sets the bounding coordinates of your viewport.
Client Size vs. Viewport Size
The client size is the size of the entire RuneScape game within the SMART client. This is commonly 800x600. The viewport is the size of the 3D world within RuneScape, usually referred to in SRL-6 terms as the mainscreen. For accurate model positioning to work, you need to ensure your viewport is correctly set with ogLib. If you do not do this, debugged model IDs will be vastly offset from their actual positions. If using resizable mode without any special alterations, your viewport will match the client size. The following images demonstrate this concept:
By default, ogLib assumes 800x600 client dimensions, and a viewport of the same size (resizable mode). These default values can be more easily called by simply writing
ogl.setup() without any parameters. The default values can be changed using
ogl.setDefaultClientHeight() and
ogl.setDefaultClientWidth(). When ogLib is set up, it loads the default cache time, color tolerance, controls - auto-retaliate, familiar action, quick heal, quick prayer, and size, if needed. These can be changed with
ogl.setDefaultCacheTime(),
ogl.setDefaultControlAutoRetaliate(), et cetera.
To save all of the current SMART's parameters, mentioned above, as defaults, use
ogl.save().
Part 4 :: Retrieving Chars, Models, and Textures
What makes OpenGL and ogLib so powerful is their ability to instantly locate chars, models, and textures on the screen. Or, equally important, it can be used to tell you if something is not present on the screen. To do this, we have the vital methods
ogl.getChars(),
ogl.getModels(), and
ogl.getTextures().
Each of the above methods can be used to find their respective types on the screen. See the sample
Script 4.1 below.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
procedure mainLoop;
var
textureArray: glTextureArray;
begin
textureArray := ogl.getTextures(1275);
writeln(textureArray);
end;
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
repeat
mainLoop;
until false;
end.
In the example above, 1275 is the texture ID of the red flag that appears whenever a player is moving or beginning an interaction with a game object. You can also get every char, model, or texture currently on the screen by not using any limiting search parameter. A returned texture array might look something like this:
Code:
[{ID = 33556, COLOURID = 2432529, FULLCOLOURID = 2630421, X = 912, Y = 528, BOUNDS = {X1 = 0, Y1 = 0, X2 = 1824, Y2 = 1057}},
{ID = 57120, COLOURID = 2894355, FULLCOLOURID = 2631441, X = 912, Y = 457, BOUNDS = {X1 = 884, Y1 = 455, X2 = 940, Y2 = 460}}]
To visually debug texture and model IDs, you can use the
ID Highlighting Tool. Or, you can use ogLib's debug functions, shown in the sample
Script 4.2 below:
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
ogl.setDebugMode('none');
ogl.setDebugMode('texture');
ogl.setDebugMode('model');
ogl.setDebugMode('font');
ogl.setDebugMode('nones');
ogl.setDebugMode('textures');
ogl.setDebugMode('models');
ogl.setDebugMode('fonts');
ogl.setDebugMode('N');
ogl.setDebugMode('T');
ogl.setDebugMode('M');
ogl.setDebugMode('F');
ogl.setDebugMode(0);
ogl.setDebugMode(1);
ogl.setDebugMode(2);
ogl.setDebugMode(3);
end.
ogl.setDebugMode() is very flexible in what it accepts: if you want to debug onscreen models, you can use
ogl.setDebugMode('models'),
ogl.setDebugMode('M'), or
ogl.setDebugMode(2), whichever you find more convenient! Doing so will cause these IDs to appear on SMART's debug:
Depending on your screen resolution, the green ID numbers may appear differently. Use ingame zooming and camera movement to see the numbers more clearly if needed. If too many models are stacked on top of each other, you will need to use text debugging methods such as
writeln(ogl.getModels()).
Part 5 :: Basic Scripting with OpenGL
To start off with, scripting with OpenGL can be much different then using colour. Before continuing, we highly recommend reading @
Kevin's thread on
Function Pointers, as we'll be touching on it a lot throughout this tutorial. His methods are fantastic when used with OpenGL.
So, let's make our first very basic auto-fighter. For learning's sake, head to the
Troll Brutes in Burthorpe.
- Step 1 - Starting the OpenGL plugin
To start using the OpenGL plugin, we need to create a basic script, beginning with our basic setup call mentioned earlier.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
end.
- Step 2 - Setting graphics settings
To use the OpenGL plugin, our client must be also be using OpenGL. You'll need to make your graphics settings match the following image:
- Step 3 - Debugging models
Now that we've correctly loaded the client, we need to debug some models in order to locate the Troll brutes.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
ogl.setDebugMode('models');
end.
Using this, we can then locate the correct model IDs. These have been highlighted in the image below:
- Step 4 - Locating models
Now it's time to find the trolls using ogl.getModels() and their model ID of 403123861.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
procedure mainLoop;
var
trollBrutes: glModelArray;
begin
trollBrutes := ogl.getModels(403123861);
clearDebug;
if trollBrutes.isEmpty() then
writeln('No troll brutes were found.')
else
begin
writeln(trollBrutes.indexes(),' troll brutes were found:');
writeln(trollBrutes);
end;
wait(150);
end;
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
ogl.setDebugMode('models');
repeat
mainLoop;
until false;
end.
This script should print something along the lines of:
Code:
8 Troll brutes found:
[{ID = 403123861, TID = 706, X = 658, Y = 670}, {ID = 403123861, TID = 706, X = -20, Y = 414}, {ID = 403123861, TID = 706, X = 352, Y = 348}, {ID = 403123861, TID = 706, X = 629, Y = 364}, {ID = 403123861, TID = 706, X = 367, Y = 207}, {ID = 403123861, TID = 706, X = 261, Y = 184}, {ID = 403123861, TID = 706, X = 301, Y = 151}, {ID = 403123861, TID = 706, X = 278, Y = 133}]
- Step 5 - Interacting with models
Now that we know how to locate the trolls, let's start attacking the closest to the center.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
procedure mainLoop;
var
trollBrutes: glModelArray;
begin
trollBrutes := ogl.getModels(403123861);
clearDebug;
if trollBrutes.isEmpty() then
writeln('No troll brutes were found.')
else
mouse.click(clientCenter.closest(trollBrutes)[0].randomizePointEllipse(15));
wait(random(1000, 2000));
end;
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
clientCenter := ogl.getClientMidPoint();
repeat
mainLoop;
until false;
end.
- Step 6 - Debugging advanced models
While Script 5.4 attacks the Troll brutes, it doesn't stop once in combat. To fix this, we need to also detect the target reticule models. There are two indicating that we are in combat:
- Red: Target.
- Red and Yellow: Retaliating target.
- Yellow: Aggressive monster.
The image below shows that visually debugging models isn't always easy:
Therefore, we need to resort to the debug window and use ogl.getModels() to its full potential - retrieving all models on screen. As you can see from Figure 2.3, there can be thousands of models on screen, so attempt to zoom in to narrow the search as much as possible and edit the script.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
var
clientCenter: TPoint;
procedure mainLoop;
var
allModels, trollBrutes: glModelArray;
begin
allModels := ogl.getModels();
clearDebug;
writeln(allModels);
wait(250);
{
trollBrutes := ogl.getModels(403123861);
if trollBrutes.isEmpty() then
writeln('No Troll brutes found.')
else
mouse.click(clientCenter.closest(trollBrutes)[0].randomizePointEllipse(15));
wait(random(1000, 2000));
}
end;
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
clientCenter := ogl.getClientMidPoint();
repeat
mainLoop;
until false;
end.
If done correctly, your debug window should contain something similar to the following figure. Copy the contents into Notepad or any text editor.
Code:
[{ID = 487932993, TID = 107, X = -197, Y = 669}, {ID = 208265157, TID = 84, X = -28, Y = 591}, {ID = 528332493, TID = 195, X = 780, Y = 695}, {ID = 2410841246, TID = 121, X = 539, Y = 603}, {ID = 3258171939, TID = 53, X = 249, Y = 597}, {ID = 3587280739, TID = 248, X = 798, Y = 462}, {ID = 4105139511, TID = 59, X = 265, Y = 452}, {ID = 545440014, TID = 60, X = 277, Y = 326}, {ID = 403123861, TID = 706, X = -87, Y = 141}, {ID = 3097012422, TID = 135, X = 239, Y = 173}, {ID = 545440014, TID = 45, X = 93, Y = 135}, {ID = 4105139511, TID = 59, X = -1, Y = 143}, {ID = 2477500689, TID = 49, X = -68, Y = 66}, {ID = 427589626, TID = 80, X = 687, Y = 90}, {ID = 1580736461, TID = 57, X = 4, Y = -1}, {ID = 4105139511, TID = 29, X = 853, Y = 20}, {ID = 2297058922, TID = 62, X = 323, Y = -58}, {ID = 528332493, TID = 130, X = 450, Y = -72}, {ID = 1279548371, TID = 49, X = 827, Y = -36}, {ID = 0, TID = 0, X = 0, Y = 0}, {ID = 0, TID = 0, X = 2821, Y = -1545}, {ID = 403123861, TID = 706, X = 520, Y = 336}, {ID = 1452224228, TID = 21, X = 520, Y = 336}, {ID = 1212609603, TID = 1444, X = 400, Y = 331}, {ID = 2209194569, TID = 18, X = 45, Y = -122}, {ID = 0, TID = 0, X = -2278, Y = -5033}]
We know the model ID of the troll and it appears to share the exact coordinate of the reticule, so first find the glModel entry belonging to the troll. In this case, you'll see that its coordinates are (520, 336). You can quite literally copy the "X = 520, Y = 336" and search the record for an exact match, belonging to the ID 1452224228.
- Step 7 - Extracting models
Now that we have the ID for the target reticule, we need to detect when it exists and only attack if it does not.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
var
allModels, targetReticules, trollBrutes: glModelArray;
canAttack: tCountDown;
clientCenter: TPoint;
procedure mainLoop;
begin
allModels := ogl.getModels([1452224228,403123861]);
targetReticules := allModels.getModels(1452224228);
trollBrutes := allModels.getModels(403123861);
if trollBrutes.isEmpty() then
writeln('No Troll brutes found.')
else if targetReticules.isEmpty() then
mouse.click(clientCenter.closest(trollBrutes)[0].randomizePointEllipse(15));
end;
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
clientCenter := ogl.getClientMidPoint();
repeat
mainLoop;
until false;
end.
- Step 8 - Delaying reactions
The script will now correctly only attack if you are currently not in combat. However, it still tends to rapidly click until the reticule appears. So lets split the attacking into a reaction procedure and only call it if a given time has passed. To do this, we're going to use a procedure pointer and a tCountDown. A countDown is a custom type in ogLib, similar to the countDown in SRL-6, keeping track of time for various activities. This allows the script to continue functioning without static waits like wait(random(5000));
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
var
allModels, targetReticules, trollBrutes: glModelArray;
canAttack: tCountDown;
clientCenter: TPoint;
procedure attackTrollBrute;
begin
mouse.click(clientCenter.closest(trollBrutes)[0].randomizePointEllipse(15));
canAttack.setTime(random(250, 1500));
end;
procedure doNothing;
begin
writeln('We did nothing!');
end;
procedure mainLoop;
var
reaction: procedure() = @doNothing;
begin
allModels := ogl.getModels([1452224228, 403123861]);
targetReticules := allModels.getModels(1452224228);
trollBrutes := allModels.getModels(403123861);
if trollBrutes.isEmpty() then
writeln('No Troll brutes found.')
else if targetReticules.isEmpty() and canAttack.isFinished() then
reaction := @attackTrollBrute;
reaction();
end;
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
clientCenter := ogl.getClientMidPoint();
repeat
mainLoop;
until false;
end.
- Step 9 - Using multiple reactions
Script 5.7 works very well. However, what happens when there are no troll brutes visible, or the closest one happens to be behind an interface such as the inventory? We need to find more by rotating the compass and changing the camera angle. For this, we need to add a new reaction.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
var
allModels, targetReticules, trollBrutes: glModelArray;
canAttack: tCountDown;
clientCenter: TPoint;
procedure attackTrollBrute;
begin
mouse.click(clientCenter.closest(trollBrutes)[0].randomizePointEllipse(15));
canAttack.setTime(random(250, 1500));
end;
procedure doNothing;
begin
writeln('We did nothing!');
end;
procedure rotateCamera;
begin
minimap.setDegrees(random(45, 90));
end;
procedure mainLoop;
var
reaction: procedure() = @doNothing;
begin
allModels := ogl.getModels([1452224228,403123861]);
targetReticules := allModels.getModels(1452224228);
trollBrutes := allModels.getModels(403123861);
if trollBrutes.isEmpty() or clientCenter.closest(trollBrutes)[0].isVisible() then
reaction := @rotateCamera
else if targetReticules.isEmpty() and canAttack.isFinished() then
reaction := @attackTrollBrute;
reaction();
end;
begin
ogl.setup([800, 600], [0, 0, 800, 600]);
clientCenter := ogl.getClientMidPoint();
repeat
mainLoop;
until false;
end.
- Step 10 - Debugging textures
Now that our bot fights and correctly searches for trolls, we need to start picking up and interacting with drops. For now, we'll pick up and bury bones. To do so, you'd get the model ID of bones in the same way you got the Troll brute ID. To save some time, their model ID is 2406257549.
It's time to start debugging some textures.
Tip: When debugging inventory items, it's much easier to temporarily switch to Legacy mode.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
var
allModels, targetReticules, trollBrutes: glModelArray;
canAttack: tCountDown;
clientCenter: TPoint;
procedure attackTrollBrute;
begin
mouse.click(clientCenter.closest(trollBrutes)[0].randomizePointEllipse(15));
canAttack.setTime(random(250, 1500));
end;
procedure doNothing;
begin
writeln('We did nothing!');
end;
procedure rotateCamera;
begin
minimap.setDegrees(random(45, 90));
end;
procedure mainLoop;
var
reaction: procedure() = @doNothing;
begin
allModels := ogl.getModels([1452224228,403123861]);
targetReticules := allModels.getModels(1452224228);
trollBrutes := allModels.getModels(403123861);
if trollBrutes.isEmpty() or not clientCenter.closest(trollBrutes)[0].isVisible() then
reaction := @rotateCamera
else if targetReticules.isEmpty() and canAttack.isFinished() then
reaction := @attackTrollBrute;
reaction();
end;
begin
ogl.setup(800, 600);
clientCenter := ogl.getClientMidPoint();
ogl.setDebugMode('textures');
{
repeat
mainLoop;
until false;
}
end.
Script 5.9 will change your debug mode from models to textures, changing our client to look like the following image:
From this, we can see that Bones, while in the inventory, have a texture ID of 52275.
- Step 11 - Interacting with textures
Now that we've got the texture ID of Bones, let's have it take and bury bones while fighting Troll brutes.
Simba Code:
program ogLib;
{$i ogLib\lib\core\core.simba}
var
allModels, bonesModels, targetReticules, trollBrutes: glModelArray;
bonesTextures: glTextureArray;
canAttackTrollBrute, canBuryBones, canTakeBones: tCountDown;
clientCenter: TPoint;
procedure attackTrollBrute;
var
clickPoint: TPoint;
begin
clickPoint := clientCenter.closest(trollBrutes)[0].randomizePointEllipse(15);
if random(2) then
mouse.click(clickPoint)
else
mouse.rightClickOption(clickPoint, 'Attack');
canAttackTrollBrute.setTime(random(1000, 5000));
canTakeBones.setTime(random(1000, 5000));
end;
procedure buryBones;
var
clickPoint: TPoint;
begin
clickPoint := mouse.getPoint().closest(bonesTextures)[0].randomizePointEllipse(36);
if random(2) then
mouse.click(clickPoint)
else
mouse.rightClickOption(clickPoint, 'Bury');
canBuryBones.setTime(random(250, 1500));
end;
procedure doNothing;
begin
writeln('We did nothing!');
end;
procedure rotateCamera;
begin
minimap.setDegrees(random(45, 90));
end;
procedure takeBones;
var
clickPoint: TPoint;
begin
clickPoint := clientCenter.closest(bonesModels)[0].randomizePointEllipse(15);
mouse.rightClickOption(clickPoint, 'Take Bones');
canTakeBones.setTime(random(1000, 5000));
canAttackTrollBrute.setTime(random(1000, 5000));
end;
procedure mainLoop;
var
reaction: procedure() = @doNothing;
begin
allModels := ogl.getModels([1452224228, 2406257549, 403123861]);
bonesModels := allModels.getModels(2406257549);
targetReticules := allModels.getModels(1452224228);
trollBrutes := allModels.getModels(403123861);
bonesTextures := ogl.getTextures(52275);
if (not bonesTextures.isEmpty()) and canBuryBones.isFinished() then
reaction := @buryBones
else if (not bonesModels.isEmpty()) and canTakeBones.isFinished() then
reaction := @takeBones
else if trollBrutes.isEmpty() or not clientCenter.closest(trollBrutes)[0].isVisible() then
reaction := @rotateCamera
else if targetReticules.isEmpty() and canAttackTrollBrute.isFinished() then
reaction := @attackTrollBrute;
reaction();
end;
begin
ogl.setup(800, 600);
clientCenter := ogl.getClientMidPoint();
repeat
mainLoop;
until false;
end.
If you followed along correctly, your bot should function like
this YouTube video.
Part 6 :: ogLib Development Thread
The official development thread for ogLib can be found here:
ogLib Development. This thread will serve as a reference for the continuing improvement and development of ogLib. Any questions or suggestions regarding development should be posted there - any educational questions related to using the library should be posted on this tutorial thread!
Part 7 :: Conclusion
We hope that you have as much fun trying your hand at OpenGL as we have! As said before, the ogLib project is a work in progress. Updates to the plugins themselves, as well as to ogLib, are under way to allow even more capabilities within the 3D world. This tutorial's function list will be maintained with the latest changes. Eventually, we plan to have an include library as comprehensive and complete as SRL-6. Feel free to offer your thoughts on the thread!
ogLib GitHub: https://github.com/ObscuritySRL/ogLib
Best of luck with your botting endeavors!
Clarity & Obscurity