Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Topics - dreamerman

From time to time there are nice deals on game related software, assest's or programming books on different websites, I thought that would be easier to inform about them in a single topic with little description so anyone interested would easily check basic info about particular bundle/deal.
Personally I check bundles on Humble Bundle, Fanatical and, if you will find something not mentioned here don't hesitate to post it.

To start, there is Melodic Mayhem: A Comprehensive Audio And Music Bundle on Humble Bundle
It contains royalty-free music tracks and sound effects for games, full price isn't high for what if offers, whole pack is something around 20GB of assets.
8 items -> €1
23 items -> €13.85
45 items -> €18.47
End date: 14.03.2024

Music packs: Magical, Western, Orchestral Ambient, Electronic Ambient, Chiptune Music, Casual, Synth Fantasy, Nordic, Orchestral Rock, Industrial, Synthpop, Rhythmic, Fantasy, Unreal, Unity, Godot, Ambient, Classical, Electronic, Hip Hop, Horror, Japanese.
Sound FX packs: Impacts, Fire, Horror & Suspense, Hollywood Action, Medieval Sound, Environmental Ambiences, Cyberpunk, Foley: Footsteps, Foley: Appliances, Foley: Movement & Locomotion, Vehicles: Cars, Steampunk, Jingles & Stingers, Computers & Machines, Simple Magic, Microscale: Bugs, Casual & Mobile, Water, UI & Menus, Science Fiction.
and plugins for popular game engines.

I wish You all Merry Christmas spent with your family without worrying about everyday problems and Happy New Year, may the coming year be simply better than previous, and have a great New Year's Eve party.

Best Wishes ;)
I'm currently playing with some maze generation algorithms for my logic/puzzle game pack, didn't see any such topic here on forum, so I thought that sharing this could be a good idea. Some maze generation examples available on web have nice visualization, just hope that my would be sufficient to show how each algorithm work. Project includes implementation of several most common maze generation algorithms like: Binary Tree, Sidewinder, Hunt&Kill, DFS/Backtracker, Eller, Prim, Growing Tree. Some were modified to add difficulty variation - mostly length of walk in current direction.
One major addition would be bridges (paths above/beneath another), those simple algorithms have limited possibilities for that, and needs to be used in combination or as addition to some other techniques - like regions, pre-calculating bridge positions and so on. Last algorithm - Growing Tree has basic bridge logic implemented.

One thing that code can be a little messy, most time I use Javascript for such prototyping and code was ported to GLB to share on forum (GLB is also target/final language). Feel free to modify, and new functions.

-+ -> switch algorithm
[] -> change map width
<> -> change map height
space -> generate maze
escape -> end
As we know current racial situation in USA is tense, maybe due that or it was planned earlier but is running now a 'Bundle for Racial Justice and Equality', goal was to reah $5kk, already exceed that amount. Regardless the reason, beside helping this noble goal it's good opportunity to dig on for some interesting stuff. In short words, for at leas $5 You can get content from 1320 creators -> "Buy 1,657 items for $5 Regularly ~$9,193 Save 99%!". It's running from some time but will be available for next 3 days.
Ofc moslty contains game projects, but also some tileset's and other 2d stuff like animations, sprites and so on.
link to bundle

Some time ago I saw one quite original concept game, it's in this bundle so I decided to make a hint about it:
Quote from: dev descriptionLazerGrrl is a fast-paced pvp strategy game. It combines the fury of Bomberman with the strategic depth of an RTS. Find the right balance between building your own base and blasting your opponents.

If You saw some interesting project, great art or original concept don't hesitate to write Your opinion ;]
Hi, unfortunatelly during final release tests of my project I encoutered serious bug in Steam version v16.
Trying to load sprite larger than 128px from shoebox will fail with fatal error like this:
Code (glbasic) Select
Error: 3. Not a JPEG file: starts with 0x02 0x00
This wasted me couple of hours figuring what's wrong with my game, as that info is outputted in stderr stream so wont appear in editor, and I forgot to include stderr in *bat file for outputting stdout..
Problem appears in v16 (Steam version), I checked and v15 ofc is working properly.
Simple project to show the issue. Baisically put larger sprite like 1024x1024px in shoebox then:
Code (glbasic) Select
SETSHOEBOX "Media.sbx", ""
LOADSPRITE "sprite.png", 0

Will crash app... Hope that this will be an easy fix ;-)

Current version: 09.03.2022

This is my attempt to use Steam API or rather some of its parts in GLbasic. Yeah, it isn't clean code, not bullet-proof, and have some issues, it's still under constant development to fit my needs. Most important thing is that, user stats and achievements are working, tested on live app, leaderboards are under testing.

Download consist of two files:
steam_sdk.gbas -> imports for proper Steam API functions from dll, only part of functions were tested.
stats_manager.gbas -> Stat Manager type/object, main thing simplify using Steam stuff in game, supports user stats (int, float), achievements, leaderboards/highscore, and some help functions.

Take note, that if You will run project from Steam version GLBasic editor it will inherit its app_id, so You want be able to test it properly, not sure if putting 'steam_appid.txt' into project exe path should fix that, but You may need to either grab STDOUT to file or use alternative editor/older version.
Also read this:

How to use.
First create userstats, achievements, leaderboards on steamworks app admin panel.
Setup in game code:

1. set some object/udt for stats manager
Code (glbasic) Select
GLOBAL mySteam AS stats_manager_object, i1%

2. set all
userstats, achievements - max value for stats to unlock achievements
Code (glbasic) Select

mySteam.addUserStat("games_played", 10, 0, 0, 2) // 2 because '10games_played' achievement has such index in our in-game array
mySteam.addUserStat("elixirs_collected", 100, 0, 1, 3) // this is rapidly changing userstat

leaderboards - info, names
Code (glbasic) Select
// if you want to use avatars create sprite for storing them - should be large to contain hundreds small avatars
mySteam.setLeaderboarOptions(1, 1)
CREATESCREEN 10, 10, 1024, 1024
mySteam.setAvatarsBufferInfo(9, 10)

3. fetch leaderboards main handles - provided by Steam (stats for current user are called in Init() internally, and processed with first RunFrame())
Code (glbasic) Select

4. additional setup:
to receive info when leaderboard is ready add this function:
Code (glbasic) Select
FUNCTION StatManager_LeaderboardReady%: handle AS int64, tab_id%, top_or_near%
    LOCAL i1%, pid%, tnick$
IF (game_menu% = CONST_HIGHSCORES)
IF (tab_id% = 0 AND top_or_near% = 0)
FOR i1% = 0 TO mySteam.leaderboards[tab_id%].top_count% - 1
pid% = mySteam.leaderboards[tab_id%].top_entry[i1%].id_onlist%
tnick$ = mySteam.usersinfo_list[pid%].nickname$
STDOUT "score: " + i1% + ": " + mySteam.leaderboards[tab_id%].top_entry[i1%].score% + " - " + tnick$ + "\n"
// avatars are stored on sprite defined with setAvatarsBufferInfo(), rectangle position left-top: mySteam.usersinfo_list[pid%].image_pos.x%, mySteam.usersinfo_list[pid%].image_pos.y%, mySteam.settings.avatars_size_px%, mySteam.settings.avatars_size_px%

additional functions that may be usefull:
Code (glbasic) Select
StatManager_LeaderboardScoreUploaded() // called when score was uploaded

FUNCTION GLB_READ_ARGS%: caller_type% // to get cmd line arguments from Steam - when app is launched from browser
    LOCAL game_mode% = -1
    IF (caller_type% > 0)       // new query parameter
        game_mode% = Steam_API_Apps_GetLaunchQueryParam$("gamemode")
    IF (game_mode% > -1)
// navigate to that game mode

Usage after succesfull initialization:
Stats/achievements are ready to use after few RunFrame() calls, leaderboards after fetching handles - may take few extra ms.

for rapidly incremented userstats - destroyed enemies, items picked, doors unlocked...
Code (glbasic) Select
mySteam.updateUserStat(1, "elixirs_collected", 1, 0) // thats it, if this stat will reach its max/unlock value, 'mySteam.storeUserStats(0)' will be called automatically and proper achievement popup will be shown

for other achievements - beat some score to unlock use this:
Code (glbasic) Select
IF (match_points% >= 1000 AND mySteam.achievements_list[0].unlocked% = 0) THEN mySteam.unlockAchievement(0, "points_1000", 0)
IF (match_points% >= 3000 AND mySteam.achievements_list[1].unlocked% = 0) THEN mySteam.unlockAchievement(1, "points_3000", 0)
mySteam.storeUserStats(0) // this will show Steam achievement popup

to refresh leaderboards, for example when user clicks to 'Highscore' button in menu:
Code (glbasic) Select
mySteam.leaderboardRefresh(-1) // can be called in some longer intervals to get current/updated highscore

upload new score with
Code (glbasic) Select
mySteam.uploadHighscore(leaderboard_id%, user_score%, "")

If you will have any questions or issues let me know.
Soon more will come here...


Finally after long time my first finished GLBasic game is comming to Steam (currently only for Windows).
Nothing special, more as a test that I can do it and finish work on that project, generally it's a bundle/pack of few logical/puzzle games.

Little back story: some games started as Symbian OS projects years ago, coded with QML/JS and released on official Nokia/Ovi store, remade later in GLBasic and enchanced.
Games are 'inspired' by already available titles, nothing original just done in the way that I like it.
At first I was aiming to release all games seperately (with in-app advertising) yet during to long developement time and possible Steam release I choosed to bundle them.

Technical stuff:
At beggining I wanted to use GLBasic as ultimate tool, yet as we know future Android/iOS platform status makes this hard/impossible, despite this I wanted to at least check other platforms, so I ported game to pure HTML5/JS with Canvas based drawing.
HTML5/JS port is used on Android (with Cordova), Windows Store (desktop and phones), LG TV, Vewd and possible others.
Steam version is made with GLBasic, it has gui with fancy transition animations and this will be main version to add possible enchantements, additional games or whatever.
As You may surely assume, I don't have any special / big expectations for this release, just to pave the way, enter this market and see how all things like project management in store are done.

Next in line are two GLBasic games, that are already waiting from some time, target platform is also Steam.

Steam link
YouTube video
For some reason YT video doesn't work.. hm..

PS. other versions links:
Android, Windows Store, LG TV Store...
Vewd / Opera TV platform is still waiting for approval...

ps2. Maybe it would be better to have some kind of 'Steam Thread' to post all GLB projects available there in that topic, for such small releases it would be better.
Sadly original post is lost due that hacker issue so this is at least part of it...

My question is: How do you promote your Android/iOS (and also Win/Steam) games? is good site, but it's for people that already are interested in indie gaming, so it has limited user base? And from what I see most games on it are rather demos/alpha projects.
Kickstarter (or other such sites), great for bigger teams, not single developer (or duo dev + artist) as it's highly advised (in my opinion) to have dedicated PR man to handle all those Goals/material gifts/social media/and so on stuff.
Earlier Steam Greenlight was place that you could pick some interesting projects from tons on crap games, now only Steam Early Access remains, yet still you can search on it for something interesting. But most promotion goes for games from larger teams or those that are closest to finish as final product. And that's obvious.
All above also in some way require that your game/idea is original or at least really good designed / polished.

What ideas you have to promote small / simple games that aren't unique in most part?
Any sites/FB groups dedicated for reviews of such games, or even sponsored promotion (if they have really active user base).
This is open topic so every idea counts.

Make giveaways on SteamGifts site (or similar), use good games from bundle (HumbleBundle, BundleStars, IndieGala and so on) to attract users. Potentialy up to couple thousands may see your game, or even download it if it's free...
Make good free mobile app that would have big/huge user base, and put advertisement of your games in it, not AdSense or other such that won't give proper earnings. All depends on time needed to make such app and possible user base, for example, free app that would show graphical banners (such as in forums) from popular online games (WoW, WoT, LoL, HS, CS whatever) as Android widgets...

My publishing experience is limited to Symbian OS (that dead os from Nokia), and on it even indie developer could get attention from users. Each app category (like games/puzzles) had several subgroups: top paid, top free, last updated and so on - and that wasn't limited to top5, but it was much longer. Also popular games could get spot on banner on main page, and some other like this.
Of course, every market / ecosystem is specific, so it's hard to compare newer systems with it. For example there were sites like AllAboutSymbian, and you could send them your games to review so they would be exposed to some number of active users / potential customers and so on...
Few days ago I've uploaded my pack of logical games to Windows Store and will see how it will go there. This will be opportunity to check how active is that market, and other ways to get attention.

ps. If you have Windows/WinPhone at least 8.1 use this code to get free version of my game: 67KVC-T6YF3-K6QRF-KW29K-49GTZ
Windows Store link: CLICK
I will delete this part after code will lost validity.
Many years ago I've written an VB app to solve polynomials and draw graphs for them, key part of that project were routines for calculating simpler math stuff with keeping the proper order of performing mathematical operations. And that basically this code is, a simple math parser.
How to use it? First init with 'GOSUB math_parser_init', add your custom variables like 'x' with 'mp_add_iconst("x", 21)', and then just calculate with 'parse_math_cmd$(your_string$)' (you can also add custom functions) for example:
Code (glbasic) Select
GLOBAL user_str$, x_val$ // for inputed stuff
GOSUB math_parser_init

PRINT "Please type x value:", 10, 10
INPUT x_val$, 10, 20
mp_add_iconst("x", x_val$)
PRINT "Write equation below", 10, 30
INPUT user_str$, 10, 40
user_str$ = parse_math_cmd$(user_str$)
PRINT "result: " + user_str$, 10, 50
DEBUG "result: " + user_str$

You can use this for gui positioning/animations: button.left = integer(parse_math_cmd$("screen_width-20"))
or more advanced calculator app: result = parse_math_cmd$("2sin(0.5)+3(pi+int(1.1))-fps")
and so on...
I'm just curious if any of Windows10 users tried to use Desktop App Converter, app from Microsoft that can convert Win32 apps/games to Universal Windows Platform - so such converted app/game can run on both win10 - desktop & phone versions, and can be published on Windows Store. It looks that should work with GLB made games, as there is also project ANGLE that can be used to port OpenGL ES commands to DirectX..
I don't have any device with Win10 so can't test it how it really works, but I will try to do some test with older Angle branch - for win8.1, just after I will deal with some build issues - just to many Win SDK packages and different VisualStudio version installed..
Interesting thing, GetMouseCount() on my Win 8.1 laptop returns number 32, and I have only mouse connected, and one visible in sys device inspector (of course beside touchpad), no touch screen.
Is that normal in systems newer from Win 7/Vista? (as in XP/7 GetMouseCount() returns proper value) I know that Win 8 has many touch features but I would rather expect that additional mouse devices would be visible in GLB only when touch screen (if available) would receive some actions.
When using 'SystemPointer True', MouseAxis(2) -> mouse wheel info, isn't working, it's always = 0, beside that mouse functions are working ok.
But if I use SystemPointer False, then strange thing starts: mouse device 0 (SetActiveMouse 0) is that 'normal' mouse connected to pc, but mouse 1 also looks like active mouse, its X & Y position coords differs from mouse 0 only a little bit, and when physical mouse buttons are pressed both in-GLB mouse 0 & mouse 1 receive those 'clicks'.
Can someone check how it's looking on Win 10? Is this some kind of bug or rather new OS feature? :D It isn't big deal as for desktops there is no need to check additional mouse devices.
SAVESPRITE is great, but if you would need to do some transformations like mirroring, grayscale, disable one channel, add filtering or whatever, this code can be handy:

Code (glbasic) Select
//offscreen sprite to BMP saving function
//answers from this topic were useful:
//by dreamerman[at]wp[dot]pl
FUNCTION save_offscreen_bmp%: sprite_id%, file_name$
    LOCAL swidth%, sheight%, pixel_data%[]
    LOCAL extrabytes%, paddedSize%, filesize%, i1%, i2%, pos%, cx%, cy%
    GETSPRITESIZE sprite_id%, swidth%, sheight%
    extrabytes% = 4 - MOD((swidth% * 3), 4)
    IF (extrabytes% = 4) THEN extrabytes% = 0
    paddedSize% = (swidth% * 3 + extrabytes%) * sheight%
    filesize% = paddedSize% + 54
    SPRITE2MEM(pixel_data%[], sprite_id%)

        unsigned char bmp_cache[filesize];
//bmp header info       
// = {66,77, 0,0,0,0, 0,0, 0,0, 54,0,0,0, 40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0, 0,0,0,0, 0,0,0,0, 0x13,0x0B,0,0, 0x13,0x0B,0,0, 0,0,0,0, 0,0,0,0};
        for(i1=0;i1<54;i1++) {
            bmp_cache[i1] = 0;
        bmp_cache[0] = 66;
        bmp_cache[1] = 77;
        bmp_cache[2] = (unsigned char)(filesize);
        bmp_cache[3] = (unsigned char)(filesize >> 8);
        bmp_cache[4] = (unsigned char)(filesize >> 16);
        bmp_cache[5] = (unsigned char)(filesize >> 24);
        bmp_cache[10] = 54;
        bmp_cache[14] = 40;
        bmp_cache[18] = (unsigned char)(swidth);
        bmp_cache[19] = (unsigned char)(swidth >> 8);
        bmp_cache[20] = (unsigned char)(swidth >> 16);
        bmp_cache[21] = (unsigned char)(swidth >> 24);
        bmp_cache[22] = (unsigned char)(sheight);
        bmp_cache[23] = (unsigned char)(sheight >> 8);
        bmp_cache[24] = (unsigned char)(sheight >> 16);
        bmp_cache[25] = (unsigned char)(sheight >> 24);
        bmp_cache[26] = 1;
        bmp_cache[28] = 24;
        bmp_cache[34] = (unsigned char)(paddedSize);
        bmp_cache[35] = (unsigned char)(paddedSize >> 8);
        bmp_cache[36] = (unsigned char)(paddedSize >> 16);
        bmp_cache[37] = (unsigned char)(paddedSize >> 24);
        bmp_cache[38] = 19;
        bmp_cache[39] = 11;
        bmp_cache[42] = 19;
        bmp_cache[43] = 11;
        int col;
        char cr, cg, cb;
        pos = 54;
        for(cy=sheight-1;cy>=0;cy--) {
            for(cx=0;cx<swidth;cx++) {
                col = pixel_data(cy * swidth + cx);
                cb = (col & 0x00FF0000) >> 16;
                cg = (col & 0x0000FF00) >> 8;
                cr = (col & 0x000000FF);
                bmp_cache[pos] = cb;
                bmp_cache[pos+1] = cg;
                bmp_cache[pos+2] = cr;
            if(extrabytes) {
                for(i1=0;i1<=extrabytes;i1++) {
                    bmp_cache[pos+i1] = 0;
        FILE * myfile;
        myfile = fopen(file_name_Str, "wb");
        fwrite(bmp_cache, 1, filesize, myfile);

As this function uses INLINE, remember to attach also this:
Code (glbasic) Select
                extern "C" {
                        #include <cstdio>
        namespace __GLBASIC__ {

BR GLB IDE (may change)
This is my attempt to make code editor with features that standard IDE is missing.
Written in Visual Basic 2013 with .NET 4.5 and ScintillaNet 3.x, a source code editor for GLBasic. Free, full source code included (WIP project so beware of coding style).

Current version: 21.10.2021
Download link in attachments - so I can easily count them ;)

What does it look like?

Feature list:
- custom lexer for code coloring, syntax highlighting (all GLB keywords and user typed),
- code folding (Subs, Functions, Types, //#region),
- colored margins to see what part of code were modified,
- colored background for tabs with source names (color depends on source modification counter),
- customisable styles, that can be easily shared,
- bookmarks, saved in separate file,
- auto-completion (see attached gif) for both GLB keywords (full list), and dynamically typed user functions, types and variables, (includes identification of global, local variables/functions),
- hints (function arguments, comments) for all standard GLB functions, and user typed functions,
- show function/type definition (press CTRL and click on word (if it's a function) to go to its definition, works also with types and normal variables),
- quite advanced types handing - identifies nested types, functions in types and all what comes with it,
- support for older GLB v12 up to newest Steam v16 compilers,
- each project is compiled/built in separate temporary directory, skipping unchanged files during compilation (similar to IncrediBuild),
- and more, ah and full source code included,
NOTE: Not all functions have their own menus, try using same keyboard shortcuts as in standard editor.



Current issues:
- Current version of Scintilla doesn't use hard tabs (like most of modern text editors/ide), default soft tabs are 4 spaces width,
- Only basic project management,
- Not bullet-proof for errors,
- Compiling tested only for WIN32/64 platform, other platforms could be working,
- Find&Replace is binded to one Scintilla object (can't do multiple file search/replace without writing new component),
- DEBUG command doesn't work (it just don't show info), to replace it use STDOUT with this fix:
Code (glbasic) Select
extern "C" {
#include <cstdio>
namespace __GLBASIC__ {

FUNCTION stdout_fix:
setbuf(stdout, NULL);

and use 'stdout_fix()' function at start of your sources, and STDOUT as equivalent of DEBUG.

Current TODO
Fix bugs.

What you need to get it work?
1. Download and install .Net 4.5 Framework Redistributable / Client Pack, newer system have it built-in.
2. Compile any project with normal GLB IDE, and copy '' ('C:\Users\-X-\AppData\Local\Temp\glbasic' or '%temp%\glbasic') to app directory. This file is needed by glbasic compiler, but files from temp dir are always deleted, so we need to have it in some place and copy each time before compiling.
3. Run my IDE, goto 'tools->Options', type proper path to your GLBasic dir (to know where is the compiler, for example: 'C:\Program Files (x86)\GLBasic_v15'), also specify company name, save cfg.
4. Load your project, edit, select win32 platform, compile. All should work now.

Legacy projects - no longer updated.
To keep this post clean download links will be separated from main editor attachment.

BR GLD IDE ver VB 2010
Previous version of my code editor, made with VB 2010, .Net 2.0 and ScintillaNET 2.x

Pre GPC - precompiler to use with your favorite IDE
Simply it's PureBasic project with command line interface, that can open and compile GLB projects, you just need to pass any legit source code as argument, and app will handle the rest. Thats why it can be used with external code editors like SublimeText (as they can't read GLB project themselves).
This archive includes SumblimeText 'package' started by Albert here
This problem applies to Android platform with latest 11.322 GLB version, on v10 (and Android) or Win32 (either v10 or v11) there is no such problem.
In simple words, some polygons that are further are rendered over the closer ones, as if the depth function was set wrong or some z buffer parameter was incorrect. This applies to X_Drawobj and inline glDrawArrays, I tried to use glDepthFunc(GL_LESS) and with GL_LEQUAL parameter but that doesn't help, so problem is probably in some init functions.

Code (glbasic) Select

SETCURRENTDIR("Media") // seperate media and binaries?

// Create a Pyramid
X_OBJADDVERTEX -50, 0, -50, 0,0,RGB(0,0,255)
X_OBJADDVERTEX 50, 0, -50, 0,0,RGB(0,0,255)
X_OBJADDVERTEX 0, 100, 0, 0,0,RGB(255,255,255) // Peak
X_OBJADDVERTEX 50, 0, 50, 0,0,RGB(0,0,255)
X_OBJADDVERTEX -50, 0, 50, 0,0,RGB(0,0,255)
X_OBJADDVERTEX -50, 0, -50, 0,0,RGB(0,0,255)
X_OBJADDVERTEX 0, 100, 0, 0,0,RGB(255,255,255)
X_OBJADDVERTEX -50, 0, 50, 0,0,RGB(0,0,255)

X_MAKE3D 1, 500, 45 // Viewport 3D
X_CAMERA 150, 50, -200, 0, 30, 0


Another issue is glDrawElements, that doesn't work on Android, I have no idea why, no error with glGetError (returns 0), same code works on windows but not on my tablet :> Apart from that, there is an error in 'Samples\Common\gl.bas' file wrapping that function, currently it's:
Code (glbasic) Select
FUNCTION glDrawElements: mode, count, typ, indices[]
typ = GL_INT;
GLint* pi=new GLint[(int)count];
for(int i=0; i<count; ++i) pi[i]=indices(i);
OGL glDrawElements(mode, count, typ, pi);
delete[] pi;

But 'typ' => 'type' parameter for that function can only have values: GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT. So it should look like this:
Code (glbasic) Select
FUNCTION glDrawElements: mode, count, typ, indices%[]
//GLuint* pi=new GLuint[(unsigned int)count];
// for(unsigned int i=0; i<count; ++i) pi[i]=indices(i);
// OGL glDrawElements(mode, count, typ, pi);
// delete[] pi;
OGL glDrawElements(mode, count, typ, &indices(0));

And if 'indices' will be DGIntArray - % type as above there is no need to convert indices[] to GLuint, it's working without it.

polygons order attached image: left = v10, right = v11 - Android
I know it's Friday night, but the sooner the better.
One form of making $$ from games is in-app advertising, but so far we had no luck with it. Although there were attempts to make iads working on ios, but from what I see, now it does not work. That's why it's time to move on.
When it goes to writing custom ad network client there are several fundamental problems:
1. gif loading - this format is used for animated banners by some ad networks..
Now, thanks to the gif loader (available here), we can use this format so the problem disappeared.
2. user-agent string - such as in a default browser on the phone .. now we have to manually type it into code, and as you know, it will not be 100% correct with what is shown by browser.
3. uuid / imei - I do not know how it currently looks like - whether the uuid collecting applications are rejected? because, some networks require to pass encoded (eg md5) uuid or MAC address - which you can not currently retrieve in GLBasic.

After recently viewing different source codes  (eg 'ad mediator' for corona sdk) I stated that if they can use in-app advertising, we also should do it! ;] I have rewritten my old unfinished custom parser for one of ad networks, improved many things and now alpha code is ready to testing. Unfortunately I do not have any other device than my pc  so I ask you to help with testing.

Currently there are parsers for 3 ad networks: InnerActive, InMobi and madvertise - on the pc when setting test APP_ID for them, all these networks response with test banners showing that implementation is correct. Another ad networks can be easily added - it would be good if such network would have a Client API - not only sdk.

A lot of talk but how to test it?
We need real device testing, on some ready games/apps - check if ad providers response with real ads, does parsers work properly on them, and most important, does clicks are counted.

Example use of code - to see test banners:
Code (glbasic) Select
//remember to include gif loading routines
LOCAL t1%, t2%, t3%, gif_cframe%, gif_frames%, ad_loaded%, ad_frame%

Init_basad_ads(100, 1, 480, 800, "games", 20, "m", "")
basad_enableInnAct("", 0)
basad_enableInMobi("", 0)
basad_setnetorder("innact") //change to inmobi/madv, or combination "innact,inmobi,madv" - uncomment debug cmd in basad to see how networks response
while (basad_sock%<>-1)
DEBUG "error: " + basad_errcode% + " -> " + basad_errstr$ + "\n" //if all ok should return err=0

LOCAL done% = 1
CLEARSCREEN RGB(100, 50, 50)
WHILE done%
IF KEY(01); done% = 0; ENDIF

INC ad_frame%
IF (ad_frame% >= basad_banner_frames%); ad_frame% = 0; ENDIF

IF (basad_banner_frames% <> -1); DRAWANIM basad_spriteid%, ad_frame%, 10, 300; ENDIF //draw fancy ad banner

NOTE: 'madvertise' ad network need our IP address as parameter in POST body, so additional script is required to retrieve our ip, example code included in source.
Also this provider doesn't like some 'user-agents'  for example TouchPad isn't recognized = even test ads aren't served.

[attachment deleted by admin]
We can load jpg, png and bmp files, but whole gifs world was beyond our reach, until now.
From long time I was thinking about making gif importer, but LZW compression looked complicated, it still look strange ;d
But after long searches for most understandable code, I found some source in Java, and translation to GLB began..
Here it is, GIF loading code, with examples.

NOTE: I only 'converted' that module to GLBasic, real thanks should go to Jitsu Wan for his Java source.

GIF module:
Code (glbasic) Select
// --------------------------------- //
// Project: gif_loader

// No copyright asserted on this source code. May be used for
// any purpose, however, refer TO the Unisys LZW patent FOR any additional
// restrictions. I am NOT responsible IF something will not work properly.

// GLBasic GIF load port by dreamerman[at]
// heavily based on gif loader for Java ME by Jitsu Wan with reference to work done by Kevin Weiner, FM Software; LZW decoder adapted from John Cristy's ImageMagick.
// includes c++ inline
// any other info in code
// --- HOW TO USE ---
// - first initialize gif vars by calling -
// Init_Gif_loader()
// - next load gif file as sprite -
// Load_gif_file("some.gif", sprite_id%, frame_count%, frame_width%, frame_height%)
// DrawSprite sprite_id%, 0, 0
// - or load directly as animation for use with DrawAnim ... -
// Load_gif_as_anim("some.gif", anim_id%, frame_count%, frame_width%, frame_height%)
// DrawAnim anim_id%, current_frame%, 0, 0
// - that's all... -

//ver: public 2
//- public 2: added Redim's to clear image buffers

//two importants variables, set max sprite size - lower for compatibility with legacy gpu/mobile devices
GLOBAL gif_max_sprite_width% = 2048, gif_max_sprite_height% = 2048
//other gif loader variables
GLOBAL gif_curr_posx%, gif_curr_posy%, gif_currxlen%
GLOBAL gif_bytes%[], gif_file_size%, gif_error%, gif_rposition%, gif_tpixels%[], gif_framecount%
GLOBAL gif_width%, gif_height%, gif_gct_flag%, gif_gct_size%, gif_pixelaspect%, gif_bgindex%, gif_bgcolor%, gif_lastbgcolor%
GLOBAL gif_lctFlag%, gif_interlace%, gif_lct_size%, gif_islastimg%
GLOBAL gif_gctab%[], gif_lctab%[], gif_blockb%[], gif_block_size%
GLOBAL gif_delay%, gif_transparency%, gif_transIndex%, gif_dispose%, gif_lastDispose%
GLOBAL gif_MaxStackSize% = 4096, gif_prefix%[], gif_suffix%[], gif_pixelStack%[]
GLOBAL gif_ix%, gif_iy%, gif_iw%, gif_ih%, gif_done%, gif_loopcount%
GLOBAL gif_lastImage_id%, gif_lastRect%[], gif_image%[], gif_lastimage%[], gif_wholesprite%[]

//init function
FUNCTION Init_Gif_loader:

DIM gif_bytes%[2]
DIM gif_gctab%[256]
DIM gif_lctab%[256]
DIM gif_blockb%[256]
DIM gif_tpixels%[256]
DIM gif_prefix%[gif_MaxStackSize%]
DIM gif_suffix%[gif_MaxStackSize%]
DIM gif_pixelStack%[gif_MaxStackSize%+1]
DIM gif_lastRect%[4]
DIM gif_image%[256]
DIM gif_lastimage%[256]
DIM gif_wholesprite%[256]


//gif loading errors:
//1 - no such file
//2 - error with opening file
//3 - not a gif file - if it's bmp/jpg/png it will be loaded
//4 - ???
//5 - to small sprite size - to many gif frames
FUNCTION Load_gif_file: filename$, sprite_id%, BYREF frame_count%, BYREF frame_width%, BYREF frame_height%
LOCAL i1%, i2%, i3%, wp%, czs1$

gif_file_size% = GETFILESIZE(filename$); gif_error% = 0
IF (gif_file_size% = 0)
DEBUG "GIF load error: wrong file size\n"
gif_error = 1; RETURN 0
ENDIF //no file size?
// DEBUG "reading start: " + GETTIMERALL() + "\n"
wp% = GENFILE()
IF (OPENFILE(wp%, filename$, 1))
REDIM gif_bytes%[gif_file_size%]
READSTR wp%, czs1$, gif_file_size%
FOR i1% = 0 TO gif_file_size%-1
gif_bytes%[i1%] = ASC(MID$(czs1$, i1%, 1))
gif_rposition% = 6
ELSE //some error with loading file
gif_error = 2; RETURN 0

// DEBUG "reading end: " + GETTIMERALL() + ", file size: " + gif_file_size% + "\n"

gif_curr_posx% = 0; gif_curr_posy% = 0; gif_framecount% = 0
czs1$ = CHR$(gif_bytes%[0]) + CHR$(gif_bytes%[1]) + CHR$(gif_bytes%[2]) + CHR$(gif_bytes%[3]) + CHR$(gif_bytes%[4]) + CHR$(gif_bytes%[5])
IF (czs1$ = "GIF87a" OR czs1$ = "GIF89a")
// DEBUG "it's a gif file..\n"
//clear last image buffer
REDIM gif_image%[0]; REDIM gif_wholesprite%[0]; REDIM gif_lastimage%[0]
IF (gif_gct_flag%); gif_readColorTable(1); ENDIF
//redim sprite array
i1% = INTEGER(gif_max_sprite_width% / gif_width%)
gif_currxlen% = i1% * gif_width%
REDIM gif_wholesprite%[gif_currxlen% * gif_max_sprite_height%]


// DEBUG "loading end: " + GETTIMERALL() + "\n"
// DEBUG "array x-size: " + gif_currxlen% + ", loop count: " + gif_loopcount% + ", delay: " + gif_delay% + " \n"
// DEBUG "frame count: " + gif_framecount% + ", in-sprite pos: " + gif_curr_posx% + "x" + gif_curr_posy% + "\n"
IF (gif_error% = 5); DEC gif_curr_posy%, gif_height%; DEC gif_framecount%; ENDIF
REDIM gif_wholesprite%[gif_currxlen% * (gif_curr_posy%+gif_height%)] //cut of unnecessary data
//create sprite from array
MEM2SPRITE(gif_wholesprite%[], sprite_id%, gif_currxlen%, gif_curr_posy%+gif_height%)

ELSE //check if it's bmp, jpg  or png for normal loading
IF (gif_bytes%[0] = 66 AND gif_bytes%[1] = 77) OR (gif_bytes%[0] = 255 AND gif_bytes%[1] = 216) OR (gif_bytes%[0] = 137 AND gif_bytes%[1] = 80 AND gif_bytes%[2] = 78 AND gif_bytes%[3] = 71)
LOADSPRITE filename$, sprite_id%
GETSPRITESIZE sprite_id%, gif_width%, gif_height%
IF (gif_width% > 0 AND gif_height% > 0)
gif_framecount% = 1
gif_error = 3; RETURN 0
gif_error = 3; RETURN 0
frame_count% = gif_framecount%; frame_width% = gif_width%; frame_height% = gif_height%
REDIM gif_bytes%[1]
REDIM gif_wholesprite%[1]


//equivalent for LoadAnim
FUNCTION Load_gif_as_anim: filename$, anim_id%, BYREF frame_count%, BYREF frame_width%, BYREF frame_height%
LOCAL ws% = GENSPRITE(), temp%, tcount%, twidth%, theight%
temp% = Load_gif_file(filename$, anim_id%, tcount%, twidth%, theight%)
SETSPRITEANIM anim_id%, twidth%, theight%
frame_count% = tcount%; frame_width% = twidth%; frame_height% = theight%
RETURN temp%

//main loop
FUNCTION gif_readContents:
LOCAL i1%, code%, czs1$

gif_done% = 0
WHILE (gif_done% = 0)
code% = gif_read()
SELECT code%
CASE 44 //0x2C - image separator
// DEBUG "new image: " + gif_framecount% + "\n"
CASE 33 //0x21 - extension
code% = gif_read()
// DEBUG "extension: " + "\n"
SELECT code%
CASE 0xf9 //graphic control extension
// DEBUG "graphic ext: dispose: " + gif_dispose% + " \n"
CASE 0xff //application extension
// DEBUG "netscape ext \n"
czs1$ = ""
FOR i1%=0 TO 10; INC czs1$, CHR$(gif_blockb%[i1%]); NEXT
IF (czs1$ = "NETSCAPE2.0")
CASE 59 //0x3b - terminator
gif_done% = 1
CASE 0 //0x00 - bad byte
//raise error - format error?


// original comment
// Decodes LZW image data into pixel array.
// Adapted from John Cristy's ImageMagick.
FUNCTION gif_decodeImageData:
LOCAL NullCode% = -1, npix% = gif_iw% * gif_ih%
LOCAL available%, clear%, code_mask%, code_size%, end_of_information%, in_code%, old_code%, bits%, code%, count%, i%, datum%, data_size%, first%, top%, bi%, pi%

IF (LEN(gif_tpixels%[]) < npix); REDIM gif_tpixels%[npix]; ENDIF

data_size% = gif_read() //  Initialize GIF data stream decoder.
clear% = ASL(1, data_size%)
end_of_information% = clear% + 1
available% = clear% + 2
old_code% = NullCode%
code_size% = data_size% + 1
code_mask% = ASL(1, code_size) - 1
FOR code% = 0 TO clear%-1
gif_prefix%[code%] = 0
gif_suffix%[code%] = code%

         //  Decode GIF pixel stream.
         datum = bits = count = first = top = pi = bi = 0;

         while (i < npix)
             if (top == 0)
                 if (bits < code_size)
                     //  Load bytes until there are enough bits for a code.
                     if (count == 0)
                         // Read a new data block.
                         count = gif_readBlock();
                         if (count <= 0) {
                         bi = 0;
                     datum += ((gif_blockb(bi)) & 0xff) << bits; //(((int) gif_blockb(bi)) & 0xff) << bits;
                     bits += 8;

                 //  Get the next code.

                 code = datum & code_mask;
                 datum >>= code_size;
                 bits -= code_size;

                 //  Interpret the code

                 if ((code > available) || (code == end_of_information)) {
                 if (code == clear)
                     //  Reset decoder.
                     code_size = data_size + 1;
                     code_mask = (1 << code_size) - 1;
                     available = clear + 2;
                     old_code = NullCode;
                 if (old_code == NullCode)
                     gif_pixelStack(top++) = gif_suffix(code);
                     old_code = code;
                     first = code;
                 in_code = code;
                 if (code == available)
                     gif_pixelStack(top++) = first; //(byte) first
                     code = old_code;
                 while (code > clear)
                     gif_pixelStack(top++) = gif_suffix(code);
                     code = gif_prefix(code);
                 first = (gif_suffix(code)) & 0xff; //((int) gif_suffix(code)) & 0xff;

                 //  Add a new string to the string table,

                 if (available >= gif_MaxStackSize) {
                 gif_pixelStack(top++) = first; //(byte) first
                 gif_prefix(available) = old_code; //(short) old_code
                 gif_suffix(available) = first; //(byte) first
                 if (((available & code_mask) == 0) && (available < gif_MaxStackSize))
                     code_mask += available;
                 old_code = in_code;

             //  Pop a pixel off the pixel stack.

             gif_tpixels(pi++) = gif_pixelStack(top);

         for (i = pi; i < npix; i++)
             gif_tpixels(i) = 0; // clear missing pixels


FUNCTION gif_readImage:

gif_ix% = gif_readShort()
gif_iy% = gif_readShort()
gif_iw% = gif_readShort()
gif_ih% = gif_readShort()

LOCAL packed% = gif_read(), save%
gif_lctFlag% = bAND(packed%, 0x80) //1 - local color table flag
gif_interlace% = bAND(packed%, 0x40) //2 - interlace flag
//3 - sort flag, 4-5 - reserved
gif_lct_size% = ASL(2, bAND(packed%, 7)) //6-8 - local color table size
IF (gif_lctFlag%) //use local table
FOR i1% = 0 TO gif_gct_size%-1
gif_lctab%[i1%] = gif_gctab%[i1%]
IF (gif_bgindex% = gif_transIndex%); gif_bgcolor% = 0; ENDIF

IF (gif_transparency%)
save% = gif_lctab%[gif_transIndex%]
gif_lctab%[gif_transIndex%] = 0


INC gif_framecount%
//check for space
IF (gif_curr_posy% + gif_height% >= gif_max_sprite_height%)
gif_error% = 5; gif_done% = 1
IF (gif_error% = 0)
gif_setPixels() // transfer pixel data to image
IF (gif_transparency%); gif_lctab%[gif_transIndex%] = save%; ENDIF

//calculate new position in our sprite
INC gif_curr_posx%, gif_width%
IF (gif_curr_posx% >= gif_currxlen%)
gif_curr_posx% = 0
INC gif_curr_posy%, gif_height%
IF (gif_curr_posy% >= gif_max_sprite_height%)
gif_error% = 5
gif_done% = 1
// DEBUG "new position in sprite: " + gif_curr_posx% + "x" + gif_curr_posy% + "\n"


FUNCTION gif_setPixels:
LOCAL n%, i1%, i2%, i3%, i4%, i5%, i6%, dlug% = gif_width% * gif_height%, ccolor%

IF (gif_lastDispose% > 0)
IF (gif_lastDispose% = 3)
n% = gif_framecount% - 2 //use image before last
IF (n% > 0)
i1% = (n - 1) * gif_width%; i2% = 0 //x & y pos of that frame on sprite array
WHILE (i1% > gif_currxlen%)
DEC i1%, gif_currxlen%; INC i2%, gif_height%

FOR i4% = i2% TO i2% + gif_height%
i5% = gif_height% * i4%
FOR i3% = i1% TO i1% + gif_width%
gif_image%[i6%] = gif_wholesprite%[i5% + i3%]
INC i6%
ELSEIF (gif_lastDispose% = 2)
IF (gif_transparency%)
ccolor% = INTEGER(0x00000000)
ccolor% = gif_lastbgcolor%
FOR i1% = 0 TO dlug%-1
gif_image%[i1%] = ccolor%
//should be: g.fillRect(lastRect[0],lastRect[1],lastRect[2],lastRect[3]);
FOR i1% = 0 TO dlug% - 1
gif_image%[i1%] = gif_lastimage%[i1%]

         // copy each source line to the appropriate place in the destination
         int pass = 1;
         int incr = 8;
         int iline = 0;
         for (int i = 0; i < gif_ih; i++) {
             int line = i;
             if (gif_interlace) {
                 if (iline >= gif_ih) {
                     switch (pass) {
                         case 2 :
                             iline = 4;
                         case 3 :
                             iline = 2;
                             incr = 4;
                         case 4 :
                             iline = 1;
                             incr = 2;
                 line = iline;
                 iline += incr;
             line += gif_iy;
             if (line < gif_height) {
                 int k = line * gif_width;
                 int dx = k + gif_ix; // start of line in dest
                 int dlim = dx + gif_iw; // end of dest line
                 if ((k + gif_width) < dlim) {
                     dlim = k + gif_width; // past dest edge
                 int sx = i * gif_iw; // start of line in source
                 while (dx < dlim) {
                     // map color and insert in destination
                     int index = (gif_tpixels(sx++)) & 0xff;
                     int c = gif_lctab(index);
                     if (c != 0) {
                         gif_image(dx) = c;


//paste current frame to our sprite
i2% = 0; i3% = gif_curr_posy% * gif_currxlen% + gif_curr_posx%
FOR i1% = 0 TO gif_height% * gif_width% - 1
gif_wholesprite%[i3%+i2%] = gif_image%[i1%]
INC i2%
IF (i2%>=gif_width%); i2% = 0; INC i3%, gif_currxlen%; ENDIF


FUNCTION gif_readGraphicControlExt:
gif_read() //block size
LOCAL packed% = gif_read() //packed fields
gif_dispose% = ASR(bAND(packed%, 0x1c), 2) //disposal method -> dispose = (packed & 0x1c) >> 2
IF (gif_dispose% = 0); gif_dispose% = 1; ENDIF
gif_transparency% = bAND(packed%, 1) //transparency = (packed & 1) != 0;
gif_delay% = gif_readShort() * 10 //delay in miliseconds
gif_transIndex% = gif_read() //transparent color index
gif_read() //block terminator

//how many loops/repeats - does we care about it? ;]
FUNCTION gif_readNetscapeExt:
LOCAL b1%, b2%
IF (gif_blockb%[0] = 1)
b1% = bAND(gif_blockb%[1], 256)
b2% = bAND(gif_blockb%[2], 256)
gif_loopcount% = bOR(ASL(b2%, 8), b1%)
UNTIL (gif_block_size% = 0 OR gif_error% <> 0)

//read Logical Screen Descriptor
gif_width% = gif_readShort()
gif_height% = gif_readShort()
LOCAL packed% = gif_read(), dlug% = gif_width% * gif_height%
gif_gct_flag% = bAND(packed%, 128) // = (packed & 0x80) != 0
gif_gct_size% = ASL(2, bAND(packed%, 7))
// 1   : global color table flag
// 2-4 : color resolution
// 5   : gct sort flag
// 6-8 : gct size

gif_bgindex% = gif_read()
gif_pixelaspect% = gif_read()
//redim our image tables
REDIM gif_image%[dlug%]
REDIM gif_lastimage%[dlug%]

//DEBUG "info: " + gif_width% + "x" + gif_height% + ", colors count: " + gif_gct_size% + "\n"


//read one byte from gif file array
FUNCTION gif_read:
LOCAL i1% = 0
i1% = gif_bytes%[gif_rposition]
INC gif_rposition

FUNCTION gif_readShort:
RETURN gif_read() + ASL(gif_read(), 8)

//block reading
FUNCTION gif_readBlock:
gif_block_size% = gif_read()
IF (gif_block_size% > 0)
LOCAL count% = 0
FOR i2%=0 TO gif_block_size%-1
gif_blockb%[i2%] = gif_bytes%[gif_rposition+i2%]
INC gif_rposition%, gif_block_size%
RETURN gif_block_size%

FUNCTION gif_skipblock:
UNTIL (gif_block_size%=0 OR gif_error%<>0)

FUNCTION gif_readColorTable: is_global%
IF (is_global% = 1)
FOR i1%=0 TO gif_gct_size%-1
gif_gctab%[i1%] = 0xff000000 + ASL(gif_bytes%[gif_rposition+2], 16) + ASL(gif_bytes%[gif_rposition+1], 8) + gif_bytes%[gif_rposition]
INC gif_rposition, 3
FOR i1%=0 TO gif_lct_size%-1
gif_lctab%[i1%] = 0xff000000 + ASL(gif_bytes%[gif_rposition+2], 16) + ASL(gif_bytes%[gif_rposition+1], 8) + gif_bytes%[gif_rposition]
INC gif_rposition, 3

FUNCTION gif_resetFrame:
gif_lastDispose% = gif_dispose%
gif_lastRect%[0] = gif_ix%
gif_lastRect%[1] = gif_iy%
gif_lastRect%[2] = gif_iw%
gif_lastRect%[3] = gif_ih%

//lastImage = image
LOCAL dlug% = LEN(gif_image%[]), i1%
FOR i1% = 0 TO dlug%-1
gif_lastimage%[i1%] = gif_image%[i1%]
gif_islastimg% = 1

gif_lastbgcolor% = gif_bgcolor%
gif_dispose% = 0
gif_transparency% = 0
//gif_delay% = 0
gif_lct_size% = 0


example - load as sprite:
Code (glbasic) Select

SETCURRENTDIR("Media") // go to media files
LOCAL t1%, t2%, t3%
Load_gif_file("some_animation.gif", 1, t1%, t2%, t3%)
SAVESPRITE "test.png", 1

example - load as animation:
Code (glbasic) Select

SETCURRENTDIR("Media") // go to media files
LOCAL t1%, t2%, t3%, gif_cframe%, gif_frames%, done% = 1

Load_gif_as_anim("earth.gif", 3, gif_frames%, t2%, t3%)

CLEARSCREEN RGB(100, 50, 50)
WHILE done%
IF KEY(01); done% = 0; ENDIF
INC gif_cframe%
IF (gif_cframe% >= gif_frames%); gif_cframe% = 0; ENDIF
SLEEP gif_delay% //var from gif loading module
IF (gif_frames%>0); DRAWANIM 3, gif_cframe%, 10, 10; ENDIF


Edit: little update, fixed issue with not clearing image buffers..
I needed some simple app to change transparent color on sprites and prepare font file, but I have some problems with ImageMagic and I don't know Gimp or other graphic editor scripts so I decided to make my own program. :]
And here it is, it basic function are: auto-cropping images, changing selected base color into final requested color, searching for sprites on image (returning their rect/positions) - and possibility to create glBasic ready to use bitmap font from selected file - there is an attached sample font bitmap made in Gimp.. (for it use rect spacing x=6, y=20)
More info and instructions, examples of code in glB are also included.

It's win32 bin, but should work also on wine in Linux..

[attachment deleted by admin]