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.


Topics - dreamerman

Pages: [1]
1
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?

itch.io 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.

Examples:
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.

2
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$
SHOWSCREEN
MOUSEWAIT
END

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...

3
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..

4
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.

5
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: http://stackoverflow.com/questions/2654480/writing-bmp-image-in-pure-c-c-without-other-libraries
//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%)

   
   
    INLINE
        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;
                pos+=3;
            }
            if(extrabytes) {
                for(i1=0;i1<=extrabytes;i1++) {
                    bmp_cache[pos+i1] = 0;
                }
                pos+=extrabytes;
            }
        }
       
        FILE * myfile;
        myfile = fopen(file_name_Str, "wb");
        fwrite(bmp_cache, 1, filesize, myfile);
        fclose(myfile);
    ENDINLINE    
   
   
ENDFUNCTION

As this function uses INLINE, remember to attach also this:
Code: GLBasic [Select]
INLINE
        }
                extern "C" {
                        #include <cstdio>
                }
        namespace __GLBASIC__ {
ENDINLINE


6
NOTE! Description is being updated and contains info about upcoming new version of IDE.

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: 25.06.2017
Download link in attachments - so I can easily count them ;)

How it looks?


Features
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),
- customizeable 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 both GLB v12 and v14 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.


FUNCTION HINTS:

AUTO-COMPLETE:




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 platform, other platforms not working, but you can build for Android/iOS in standard IDE,
- 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]
INLINE
        }
                extern "C" {
                        #include <cstdio>
                }
        namespace __GLBASIC__ {
ENDINLINE

FUNCTION stdout_fix:
        INLINE
                setbuf(stdout, NULL);
        ENDINLINE
ENDFUNCTION
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 'glblicence.inc' ('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_v14'), 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

7
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.

Example:
Code: GLBasic [Select]
SYSTEMPOINTER FALSE
SETCURRENTDIR("Media") // seperate media and binaries?

// Create a Pyramid
 X_OBJSTART 5
 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_OBJNEWGROUP
 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_OBJEND

WHILE TRUE
 X_MAKE3D 1, 500, 45 // Viewport 3D
 X_CAMERA 150, 50, -200, 0, 30, 0
 //glDepthFunc(GL_LESS)
 X_DRAWOBJ 5, 0
SHOWSCREEN
WEND
END

SUB GLB_ON_LOOP:
ENDSUB
 

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;
        INLINE
                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;
        ENDINLINE
ENDFUNCTION
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%[]
        typ = GL_UNSIGNED_INT;
        INLINE
                //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));
        ENDINLINE
ENDFUNCTION
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

8
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
SETCURRENTDIR("Media")
LOCAL t1%, t2%, t3%, gif_cframe%, gif_frames%, ad_loaded%, ad_frame%
Init_Gif_loader()
SOCK_INIT()

Init_basad_ads(100, 1, 480, 800, "games", 20, "m", "http://www.dreamerman.netserwer.pl/script/check_it.php")
basad_enableInnAct("", 0)
basad_enableInMobi("", 0)
basad_enablemadvertise("")
basad_setnetorder("innact") //change to inmobi/madv, or combination "innact,inmobi,madv" - uncomment debug cmd in basad to see how networks response
basad_GetNewAd()
while (basad_sock%<>-1)
        basad_recvloop()
        SLEEP 100
WEND
SOCK_SHUTDOWN
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

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

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.

9
2D-snippets / Loading GIF files/animations...
« on: 2012-Aug-21 »
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]wp.pl
// 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
//Changelog:
//- 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]

ENDFUNCTION

//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))
                NEXT
                CLOSEFILE wp%
                gif_rposition% = 6
        ELSE    //some error with loading file
                gif_error = 2; RETURN 0
        ENDIF

//      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]
                gif_readLSD()
                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%]

                gif_readContents()

//              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
                        ELSE
                                gif_error = 3; RETURN 0
                        ENDIF
                ELSE
                        gif_error = 3; RETURN 0
                ENDIF
        ENDIF
        frame_count% = gif_framecount%; frame_width% = gif_width%; frame_height% = gif_height%
        REDIM gif_bytes%[1]
        REDIM gif_wholesprite%[1]

        RETURN 1
ENDFUNCTION

//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%
ENDFUNCTION

//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
                                gif_readImage()
//                              DEBUG "new image: " + gif_framecount% + "\n"
                        CASE 33         //0x21 - extension
                                code% = gif_read()
//                              DEBUG "extension: " + "\n"
                                SELECT code%
                                        CASE 0xf9       //graphic control extension
                                                gif_readGraphicControlExt()
//                                              DEBUG "graphic ext: dispose: " + gif_dispose% + " \n"
                                        CASE 0xff       //application extension
                                                gif_readBlock()
//                                              DEBUG "netscape ext \n"
                                                czs1$ = ""
                                                FOR i1%=0 TO 10; INC czs1$, CHR$(gif_blockb%[i1%]); NEXT
                                                IF (czs1$ = "NETSCAPE2.0")
                                                        gif_readNetscapeExt()
                                                ELSE
                                                        gif_skipblock()
                                                ENDIF
                                        DEFAULT
                                                gif_skipblock()
                                ENDSELECT
                        CASE 59         //0x3b - terminator
                                gif_done% = 1
                        CASE 0          //0x00 - bad byte
                                //continue
                        DEFAULT
                                //raise error - format error?
                ENDSELECT
        WEND

ENDFUNCTION


// 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%
        NEXT

INLINE
         //  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) {
                                         break;
                                     }
                         bi = 0;
                     }
                     datum += ((gif_blockb(bi)) & 0xff) << bits;        //(((int) gif_blockb(bi)) & 0xff) << bits;
                     bits += 8;
                     bi++;
                     count--;
                     continue;
                 }

                 //  Get the next code.

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

                 //  Interpret the code

                 if ((code > available) || (code == end_of_information)) {
                     break;
                 }
                 if (code == clear)
                 {
                     //  Reset decoder.
                     code_size = data_size + 1;
                     code_mask = (1 << code_size) - 1;
                     available = clear + 2;
                     old_code = NullCode;
                     continue;
                 }
                 if (old_code == NullCode)
                 {
                     gif_pixelStack(top++) = gif_suffix(code);
                     old_code = code;
                     first = code;
                     continue;
                 }
                 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) {
                     break;
                 }
                 gif_pixelStack(top++) = first; //(byte) first
                 gif_prefix(available) = old_code;      //(short) old_code
                 gif_suffix(available) = first; //(byte) first
                 available++;
                 if (((available & code_mask) == 0) && (available < gif_MaxStackSize))
                 {
                     code_size++;
                     code_mask += available;
                 }
                 old_code = in_code;
             }

             //  Pop a pixel off the pixel stack.

             top--;
             gif_tpixels(pi++) = gif_pixelStack(top);
             i++;
         }

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

ENDFUNCTION


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
                gif_readColorTable(0)
        ELSE
                FOR i1% = 0 TO gif_gct_size%-1
                        gif_lctab%[i1%] = gif_gctab%[i1%]
                NEXT
                IF (gif_bgindex% = gif_transIndex%); gif_bgcolor% = 0; ENDIF
        ENDIF

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

        gif_decodeImageData()
        gif_skipblock()

        INC gif_framecount%
        //check for space
        IF (gif_curr_posy% + gif_height% >= gif_max_sprite_height%)
                gif_error% = 5; gif_done% = 1
        ENDIF
        IF (gif_error% = 0)
                gif_setPixels()         // transfer pixel data to image
                IF (gif_transparency%); gif_lctab%[gif_transIndex%] = save%; ENDIF
                gif_resetFrame()
        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
                ENDIF
        ENDIF
//      DEBUG "new position in sprite: " + gif_curr_posx% + "x" + gif_curr_posy% + "\n"

ENDFUNCTION


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%
                        WEND

                        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%
                                NEXT
                        NEXT
                ENDIF
        ELSEIF (gif_lastDispose% = 2)
                IF (gif_transparency%)
                        ccolor% = INTEGER(0x00000000)
                ELSE
                        ccolor% = gif_lastbgcolor%
                ENDIF
                FOR i1% = 0 TO dlug%-1
                        gif_image%[i1%] = ccolor%
                NEXT
                //should be: g.fillRect(lastRect[0],lastRect[1],lastRect[2],lastRect[3]);
        ELSE
                FOR i1% = 0 TO dlug% - 1
                        gif_image%[i1%] = gif_lastimage%[i1%]
                NEXT
        ENDIF
ENDIF


INLINE
         // 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) {
                     pass++;
                     switch (pass) {
                         case 2 :
                             iline = 4;
                             break;
                         case 3 :
                             iline = 2;
                             incr = 4;
                             break;
                         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;
                     }
                     dx++;
                 }
             }
         }

ENDINLINE

//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
NEXT

ENDFUNCTION


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
ENDFUNCTION

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

//read Logical Screen Descriptor
FUNCTION gif_readLSD:
        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))
//bits:
// 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"

ENDFUNCTION

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

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

//block reading
FUNCTION gif_readBlock:
        LOCAL i1%
        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%]
                NEXT
                INC gif_rposition%, gif_block_size%
        ENDIF
        RETURN gif_block_size%
ENDFUNCTION

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

FUNCTION gif_readColorTable: is_global%
        LOCAL i1%
        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
                NEXT
        ELSE
                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
                NEXT
        ENDIF
ENDFUNCTION

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%]
        NEXT
        gif_islastimg% = 1

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

ENDFUNCTION
 

example - load as sprite:
Code: GLBasic [Select]
SETCURRENTDIR("Media") // go to media files
LOCAL t1%, t2%, t3%
Init_Gif_loader()
Load_gif_file("some_animation.gif", 1, t1%, t2%, t3%)
SAVESPRITE "test.png", 1
MOUSEWAIT
END
 

example - load as animation:
Code: GLBasic [Select]
SETCURRENTDIR("Media") // go to media files
LOCAL t1%, t2%, t3%, gif_cframe%, gif_frames%, done% = 1

Init_Gif_loader()
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
        SHOWSCREEN
WEND
END
 

:-)

Edit: little update, fixed issue with not clearing image buffers..

10
Hi,
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..

Pages: [1]