Pollyanna's Goatee











{Thursday 21st September '06}   Image-to-GBA 0.2

Download the Image-to-GBA tools and the source code to those tools, for Mac OS X, by clicking here.

These are the image conversion tools (and the source code to those tools) I released in the dark days of 2003 to try to help anybody doing homebrew GBA development on Mac OS X; I’m posting these tools here as, although I stopped offering these tools for download long, long ago, I still receive requests for the source code to these tools every few months – if only those making that request knew the horror that awaited them… These tools convert an image into a C-language header containing either a one-dimensional array of 16bit pixels suitable for GBA screen modes three or five, or two one-dimensional arrays containing 8bit pixels/colour palette indices and 16bit colour palette suitable for GBA screen mode four.

To use the tools, run part1, and choose the image to convert; then in Terminal.app cd to the directory containing the image conversion tools, and run either ./part2-16bitConversionToHeader or ./part2-16bitPaletteConversionToHeader.

The source code to part1 is known to compile in METAL BASIC 1.7.3, whilst the source code to part2-16bitConversionToHeader and part2-16bitPaletteConversionToHeader is known to compile in Project Builder 1.1.1; beyond that, I’m afraid you are on your own…

I can’t claim that the tools are particularly well-conceived or well-coded; about all I can claim is that if compared to the source code to any of my more recent releases, the source code to the tools is a good example of how far I have come as a coder in the last three years.

If I manage to tweak the (unofficial) GBASDK to run on Mac OS X 10.3 (a denizen of the iDevGames.com forum reports that the (unofficial) GBASDK runs on Mac OS X 10.4 if sufficiently tweaked) I’ll likely return to GBA coding, and to updating these tools – in particular, I never considered that images might need to share a palette, so batch conversion, or conversion of images to match a previously converted palette, will likely be the major feature of any update to these tools I release.

Changes in version 0.2 of Image-to-GBA (4th July 2003):

  • may now convert images for GBA screen mode four;
  • slashed the size of temporary files;
  • now appends “.h” suffix to the C-language header files produced;
  • slashed the time taken to convert images.

Version 0.1 of Image-to-GBA released on 2nd July 2003.



{Wednesday 31st December '97}   METAL Help ‘Mogrifier

METAL is a freeware BASIC IDE by Marin Saric of Galactic Dreams Software, and is quite a capable development tool if you’re into lateral-thinking-to-overcome-the-limitations-of-the-language-development…

METAL comes with pretty good built-in hyper-linked help/documentation; unfortunately, pretty good isn’t perfect, and the built-in help has several flaws: it can’t be printed, it can’t be searched (not that the language is that big, but…), and it can’t be copied and pasted.

So, I’ve developed METAL Help ‘Mogrifier {source code|compiled:Mac OS pre-X} to help.

METAL Help ‘Mogrifier is a minimalist application to convert .MHLP files viewable with METAL’s built-in help browser to .HTML files viewable with any web-browser.

To use, just copy the file metal_help.mhlp from METAL’s folder into the same folder as METAL Help ‘Mogrifier, and run METAL Help ‘Mogrifier; metal_help.mhlp will be converted and output as METAL Help.html.

So far, METAL Help ‘Mogrifier has been tested only with the metal_help.mhlp file included with METAL 1.0ß; as updated versions of METAL are released, METAL Help ‘Mogrifier will be updated to cope with any changes to the .MHLP file format (unless of course METAL’s built-in help browser is updated to fix the flaws which prompted the development of METAL Help ‘Mogrifier…)

METAL Help ‘Mogrifier was developed on an Apple Power Macintosh 8100 in C++ compiled with Metrowerks CodeWarrior IDE 2.1 (Discover Programming Edition.)



{Sunday 28th December '97}   PIIIC_03

I suck at maths.

I really, really suck at maths.

Given my ambitions, that I really, really, really suck at maths is an ever-so-slight problem.

So, I’ve begun to develop quick-and-dirty-and-ugly programs to further my mathematical ability; PIIIC_03 {source code & compiled:Mac OS pre-X} is the latest of those programs, a – like PIIIC_02 – 3D model viewer; where PIIIC_03 differs from PIIIC_02 is that the 3D model may be rotated about any axis, not just the y axis.

Pressing the x, y, or z key will set the current axis; pressing the left and right arrow keys will rotate the 3D model about the current axis; pressing the up and down arrow keys will zoom the 3D model out and in; and the program may be quit by pressing the escape key.

PIIIC_03 was developed on an Apple Power Macintosh 8100 in (HEAVY) METAL BASIC compiled with my HEAVY METAL 1.0ß and Galactic Dreams Software’s METAL 1.0ß.



{Saturday 27th December '97}   PIIIC_02

I suck at maths.

I really, really suck at maths.

Given my ambitions, that I really, really, really suck at maths is an ever-so-slight problem.

So, I’ve begun to develop quick-and-dirty-and-ugly programs to further my mathematical ability; PIIIC_02 {source code & compiled:Mac OS pre-X} – a 3D model viewer – is the latest of those programs; the 3D model may be rotated about the y axis by pressing the left and right arrow keys and may be zoomed in and out by pressing the down and up arrow keys respectively; perspective may be turned on and off by pressing the 1 and 0 keys respectively; and the program may be quit by pressing the escape key.

PIIIC_02 was developed on an Apple Macintosh 8100 in (HEAVY) METAL BASIC compiled with my HEAVY METAL 1.0ß and Galactic Dreams Software’s METAL 1.0ß.



{Thursday 25th December '97}   HEAVY METAL

Contents

Intro

METAL is a freeware BASIC IDE by Marin Saric of Galactic Dreams Software, and is quite a capable development tool if you’re into lateral-thinking-to-overcome-the-limitations-of-the-language-development…

However, the language has a few limitations that I feel merely irritate rather than present an interesting challenge to overcome: no support for multiple files, no support for named constants, no requirement that variables be declared/no scoping of variables, no support for parameterised functions, …

So, I’ve developed HEAVY METAL {source code|compiled:Mac OS pre-X} to try to remedy some of those limitations.

HEAVY METAL is a pre-compiler: taking one HEAVY METAL-language file (which may reference other such files) as input, one METAL-language file is output; that output file can then be compiled using METAL.

HEAVY METAL introduces several instructions to try to remedy several of the aforementioned limitations of METAL, such as instructions for declaring and calling parameterised functions, but, as a pre-compiler, is limited in the features it can introduce to METAL; however, with a bit of lateral thinking, even features such as recursive parameterised functions and polymorphic parameterised functions (planned for a future update to HEAVY METAL) can be implemented – so, if you have a suggestion for an instruction or feature, I would be happy to receive it (with the caveat that instructions and features will be implemented in the order that they are useful to me…) Similarly, I would be happy to receive reports of any bugs not included in the list below.

Every instruction introduced by HEAVY METAL begins with a ‘@’ character, and ends with a ‘ ‘ character, eg. “@new_scope·variable;” and “@delete_scope·“.

Due to METAL‘s lack of in-depth language documentation, HEAVY METAL does not try to check for errors in the METAL-language files it produces.

To use HEAVY METAL, copy all of the HEAVY METAL-language files pertaining to your project into the same folder as HEAVY METAL; run HEAVY METAL, type in the name of your project’s primary HEAVY METAL-language file and press the Return key, and that file (and any file it references) will be ‘compiled’, producing a METAL-language file with the same name as that file, and the suffix .hmet.

So far, HEAVY METAL has been tested only with METAL 1.0ß; as updated versions of METAL are released, HEAVY METAL will be updated to cope with any changes to the language (unless of course METAL is updated to remedy those limitations which prompted the development of HEAVY METAL…)

Instructions

@include | Include file

@include <file>;

Inserts the contents of <file>, which undergo the same ‘compilation’ as any other file; @include instructions may be nested, viz., a file can include another file, which can include another file, …

The file @include (name).bas:

"Mark"

The file @include (greeting).bas:

@new_scope n_suffix$;

if £n = 1 then

£n_suffix$ = "st"

else

if £n = 2 then

£n_suffix$ = "nd"

end if

end if

print "Greetings, world! This is the "; £n; £n_suffix$; " time I've greeted you! My name is " + @include @include (name).bas; + "!"

@delete_scope

The file @include.bas:

@new_scope n;

£n = 1

@include @include (greeting).bas;

@++ £n;

@include @include (greeting).bas;

@delete_scope

The result of ‘compiling’ @include.bas:

xmwpiq_n = 1

if xmwpiq_n = 1 then

nsmopg_n_suffix$ = "st"

else

if xmwpiq_n = 2 then

nsmopg_n_suffix$ = "nd"

end if

end if

print "Greetings, world! This is the "; xmwpiq_n; nsmopg_n_suffix$; " time I've greeted you! My name is " + "Mark" + "!"

xmwpiq_n = ( xmwpiq_n + 1 )

if xmwpiq_n = 1 then

ctohvj_n_suffix$ = "st"

else

if xmwpiq_n = 2 then

ctohvj_n_suffix$ = "nd"

end if

end if

print "Greetings, world! This is the "; xmwpiq_n; ctohvj_n_suffix$; " time I've greeted you! My name is " + "Mark" + "!"

@FALSE | False constant

@FALSE

Inserts METAL‘s false constant, 0.

Mark_likes_seals = @FALSE

if Mark_likes_seals then

print "All is right with the world."

else

print "Something is very wrong with the world…"

end if

Result of ‘compilation’:

Mark_likes_seals = 0

if Mark_likes_seals then

print "All is right with the world."

else

print "Something is very wrong with the world…"

end if

@TRUE | True constant

@TRUE

Inserts METAL‘s true constant, -1.

Mark_likes_seals = @TRUE

if Mark_likes_seals then

print "All is right with the world."

else

print "Something is very wrong with the world…"

end if

Result of ‘compilation’:

Mark_likes_seals = -1

if Mark_likes_seals then

print "All is right with the world."

else

print "Something is very wrong with the world…"

end if

@B | Binary constant

@B <binary constant>;

Replaces <binary constant> with the equivalent decimal constant.

print "I was born in the "; @B 111;; "th month."

Result of ‘compilation’:

print "I was born in the "; 7; "th month."

@H | Hexadecimal constant

@H <hexadecimal constant>;

Replaces <hexadecimal constant> with the equivalent decimal constant.

print "I was born in the year "; @H 7BF;; "."

Result of ‘compilation’:

print "I was born in the year "; 1983; "."

@CONSOLE | Console constant

Inserts METAL‘s console constant, 0.

w = 48

h = 48

image = init screen( 0, 0, ( w * 2 ), h )

set screen to image

loadpict "image.pict"

set screen to console

copyrect masked 0, 0, w, h, w, 0, ( w * 2 ), h, 0, 0, w, h, image, image, @CONSOLE

Result of ‘compilation’:

w = 48

h = 48

image = init screen( 0, 0, ( w * 2 ), h )

set screen to image

loadpict "image.pict"

set screen to console

copyrect masked 0, 0, w, h, w, 0, ( w * 2 ), h, 0, 0, w, h, image, image, 0

@new_scope & @delete_scope | Declaring/scoping of variables

@new_scope <variable1>,<variable2>,<…>;

<…>

£<variable>

<…>

@delete_scope

When developing in METAL, it is easy to make a mistake in typing the name of a variable, or to cause a clash with the names of variables in subs (and now parameterised functions), resulting in bugs with hard to track down causes.

To try to remedy these causes of bugs, HEAVY METAL introduces declaring/scoping of variables, at the minor cost of typing an extra character before the name of a scoped variable.

The @new_scope instructions begins a new scope, and is followed by a list of the names of the variables introduced in that scope – a scoped variable can have the same name as a non-scoped variable or a scoped variable introduced in the scope immediately prior without clashing.

To use a scoped variable, simply prefix the name of the variable with a ‘£’ character.

Scoped variable names are not case-sensitive.

The @delete_scope instruction ends a scope.

Scopes are implemented by generating a random, unique prefix for each scope; when a scoped variable is used, it is simply given that prefix.

print "This program will print the numbers 21, 7, 1983, and 1997, in that order; each number will be printed on a new line."

v = 1997

@new_scope v;

£v = 1983

@new_scope v;

£v = 7

@new_scope v;

£v = 21

print £v

@delete_scope

print £v

@delete_scope

print £v

@delete_scope

print v

Result of ‘compilation’:

print "This program will print the numbers 21, 7, 1983, and 1997, in that order; each number will be printed on a new line."

v = 1997

mnjmuu_v = 1983

xdrhri_v = 7

lujggi_v = 21

print lujggi_v

print xdrhri_v

print mnjmuu_v

print v

@begin_func, @end_func, & @func | Declaring/calling functions

@begin_func <function>:<parameter1>,<parameter2>,<…>;

<…>

@end_func

@func <function>:<parameter1>,<parameter2>,<…>;

HEAVY METAL introduces parameterised functions; the @begin_func instruction begins the declaration of a function, and is followed by the name of the function, terminated by a ‘:’ character; that is then followed by a list of the names of the parameters of the function.

The @end_func instruction ends the declaration of the function; note that the function must be explicitly returned from using METAL‘s return instruction.

Parameterised functions are implemented using subs; the names of the parameters are prefixed with the name of the function to avoid clashes with variables elsewhere in the code; the parameters are then assigned the values passed to them, and the sub is called using METAL‘s gosub instruction.

Neither function nor parameter names are case-sensitive.

If in the declaration of a function a parameter is prefixed by a ‘~’ character, the value of that parameter is passed back when returning from the function.

goto MAIN



@begin_func Highest:value1,value2,~highestValue;

if value1 > value2 then

highestValue = value1

else

highestValue = value2

end if

return

@end_func



MAIN:

@func Highest:21,7,highestValue;

print "The highest value is: "; highestValue; "."

Result of ‘compilation’:

goto MAIN



highest:

if highest_value1 > highest_value2 then

highest_highestvalue = highest_value1

else

highest_highestvalue = highest_value2

end if

return



MAIN:

highest_value1=21

highest_value2=7

highest_highestvalue=highestValue

gosub highest

highestValue=highest_highestvalue

print "The highest value is: "; highestValue; "."

@++ | Increment variable

@++ <variable>;

Inserts instructions for incrementing <variable> by 1.

m = 6

@++ m;

print "I was born in the "; m; "th month."

Result of ‘compilation’:

m = 6

m = ( m + 1 )

print "I was born in the "; m; "th month."

@– | Decrement variable

@-- <variable>;

Inserts instructions for decrementing <variable> by 1.

y = 1984

@-- y;

print "I was born in the year "; y; "."

Result of ‘compilation’:

y = 1984

y = ( y - 1 )

print "I was born in the year "; y; "."

@+= | Increase variable by

@+= <variable1>,<variable1, 2, or constant>;

Inserts instructions for increasing <variable1> by <variable1, 2, or constant>.

m = 3.5

@+= m,m;

print "I was born in the "; m; "th month."

Result of ‘compilation’:

m = 3.5

m = ( m + m )

print "I was born in the "; m; "th month."

@-= | Decrease variable by

@-= <variable1>,<variable1, 2, or constant>;

Inserts instructions for decreasing <variable1> by <variable1, 2, or constant>.

y = 1997

z = 14

@-= y,z;

print "I was born in the year "; y; "."

Result of ‘compilation’:

y = 1997

z = 14

y = ( y - z )

print "I was born in the year "; y; "."

@*= | Multiply variable by

@*= <variable1>,<variable1, 2, or constant>;

Inserts instructions for multiplying <variable1> by <variable1, 2, or constant>.

d = 7

@*= d,3;

print "I was born on the "; d; "st of July."

Result of ‘compilation’:

d = 7

d = ( d * 3 )

print "I was born on the "; d; "st of July."

@/= | Divide variable by

@/= <variable1>,<variable1, 2, or constant>;

Inserts instructions for dividing <variable1> by <variable1, 2, or constant>.

m = 21

@/= m,3;

print "I was born in the "; m; "th month."

Result of ‘compilation’:

m = 21

m = ( m / 3 )

print "I was born in the "; m; "th month."

@&= | Logically AND variable

@&= <variable1>,<variable2 or constant>;

Inserts instructions for performing a logical AND of <variable1> and <variable2 or constant>, assigning the result to <variable1>.

v = @B 111111;

print "I'm pretty sure I wasn't born on the "; v; "rd of July…"

@&= v,@B 010101;;

print "I was born on the "; v; "st of July."

Result of ‘compilation’:

v = 63

print "I'm pretty sure I wasn't born on the "; v; "rd of July…"

v = ( v and 21 )

print "I was born on the "; v; "st of July."

@|= | Logically OR variable

@|= <variable1>,<variable2 or constant>;

Inserts instructions for performing a logical OR of <variable1> and <variable2 or constant>, assigning the result to <variable1>.

v = @B 010000;

print "I'm pretty sure I wasn't born on the "; v; "th of July…"

@|= v,@B 000101;;

print "I was born on the "; v; "st of July."

Result of ‘compilation’:

v = 16

print "I'm pretty sure I wasn't born on the "; v; "th of July…"

v = ( v or 5 )

print "I was born on the "; v; "st of July."

@!= | Logically NOT variable

@!= <variable>;

Inserts instructions for performing a logical NOT of <variable>, assigning the result to <variable>.

v = @B 101010;

print "I'm pretty sure I wasn't born on the "; ( v and @B 111111; ); "nd of July…"

@!= v;

print "I was born on the "; ( v and @B 111111; ); "st of July."

Result of ‘compilation’:

v = 42

print "I'm pretty sure I wasn't born on the "; ( v and 63 ); "nd of July…"

v = ( not v )

print "I was born on the "; ( v and 63 ); "st of July."

@” | Quotation mark

@"

Inserts instructions for inserting a quotation mark character.

print "Mark " + @" + "sealfin" + @" + " Bishop"

Result of ‘compilation’:

print "Mark " + chr$( 34 )+ "sealfin" + chr$( 34 )+ " Bishop"

Bug

  • Comments are not respected, viz., HEAVY METAL instructions in comments will still be ‘compiled’; for many instructions, this is not a problem, but not for all, as the following two programs demonstrate.

    Program #1:

    rem My_name_is_Mark = @TRUE

    Result of ‘compilation’:

    rem My_name_is_Mark = -1

    Program #2:

    goto MAIN



    @begin_func Highest:value1,value2;

    @new_scope highest;

    if value1 > value2 then

    £highest = value1

    else

    £highest = value2

    end if

    print "Out of "; value1; " and "; value2; ", "; £highest; " is the highest value."

    return

    @delete_scope

    @end_func



    MAIN:

    rem @func Highest:21,7;

    Result of ‘compilation’:

    goto MAIN



    highest:

    if highest_value1 > highest_value2 then

    kydcwk_highest = highest_value1

    else

    kydcwk_highest = highest_value2

    end if

    print "Out of "; highest_value1; " and "; highest_value2; ", "; kydcwk_highest; " is the highest value."

    return



    MAIN:

    rem highest_value1=21

    highest_value2=7

    gosub highest

  • If a function calls another function, the first function’s parameters cannot be passed straight to the second, as the parameters will not be properly prefixed with the name if the first function during ‘compilation’; for now this bug can be circumvented by assigning the first function’s parameters to intermediate variables, and passing those intermediate variables to the second function; the following two programs demonstrate the bug, and circumventing the bug.

    Program #1:

    goto MAIN



    @begin_func function1:parameter1$;

    print "parameter1$: " + @" + parameter1$ + @"

    return

    @end_func



    @begin_func function2:parameter2$;

    @new_scope s$,i,c$;

    @func function1:parameter2$;

    £s$ = ""

    for £i = 1 to len( parameter2$ )

    £c$ = mid$( parameter2$, £i, 1 )

    if ( asc( £c$ ) >= asc( "a" )) and ( asc( £c$ ) <= asc( "z" )) then

    £c$ = chr$( asc( "A" ) + ( asc( £c$ ) - asc( "a" )))

    end if

    @+= £s$,£c$;

    next £i

    print "parameter2$: " + @" + £s$ + @"

    return

    @delete_scope

    @end_func



    MAIN:

    print "This program should print two strings, the second a capitalised copy of the first."

    @new_scope s$;

    £s$ = "Cower now brief mortals, for I am Death, 'gainst whom no lock will hold nor fastened portal bar"

    @func function2:£s$;

    @delete_scope

    Result of ‘compilation’:

    goto MAIN



    function1:

    print "parameter1$: " + chr$( 34 )+ function1_parameter1$ + chr$( 34 )

    return



    function2:

    function1_parameter1$=parameter2$

    gosub function1

    fjofsy_s$ = ""

    for fjofsy_i = 1 to len( function2_parameter2$ )

    fjofsy_c$ = mid$( function2_parameter2$, fjofsy_i, 1 )

    if ( asc( fjofsy_c$ ) >= asc( "a" )) and ( asc( fjofsy_c$ ) <= asc( "z" )) then

    fjofsy_c$ = chr$( asc( "A" ) + ( asc( fjofsy_c$ ) - asc( "a" )))

    end if

    fjofsy_s$ = ( fjofsy_s$ + fjofsy_c$ )

    next fjofsy_i

    print "parameter2$: " + chr$( 34 )+ fjofsy_s$ + chr$( 34 )

    return



    MAIN:

    print "This program should print two strings, the second a capitalised copy of the first."

    olqxut_s$ = "Cower now brief mortals, for I am Death, 'gainst whom no lock will hold nor fastened portal bar"

    function2_parameter2$=olqxut_s$

    gosub function2

    Program #2:

    goto MAIN



    @begin_func function1:parameter1$;

    print "parameter1$: " + @" + parameter1$ + @"

    return

    @end_func



    @begin_func function2:parameter2$;

    @new_scope s$,i,c$;

    £s$ = parameter2$

    @func function1:£s$;

    £s$ = ""

    for £i = 1 to len( parameter2$ )

    £c$ = mid$( parameter2$, £i, 1 )

    if ( asc( £c$ ) >= asc( "a" )) and ( asc( £c$ ) <= asc( "z" )) then

    £c$ = chr$( asc( "A" ) + ( asc( £c$ ) - asc( "a" )))

    end if

    @+= £s$,£c$;

    next £i

    print "parameter2$: " + @" + £s$ + @"

    return

    @delete_scope

    @end_func



    MAIN:

    print "This program should print two strings, the second a capitalised copy of the first."

    @new_scope s$;

    £s$ = "Cower now brief mortals, for I am Death, 'gainst whom no lock will hold nor fastened portal bar"

    @func function2:£s$;

    @delete_scope

    Result of ‘compilation’:

    goto MAIN



    function1:

    print "parameter1$: " + chr$( 34 )+ function1_parameter1$ + chr$( 34 )

    return



    function2:

    uduavc_s$ = function2_parameter2$

    function1_parameter1$=uduavc_s$

    gosub function1

    uduavc_s$ = ""

    for uduavc_i = 1 to len( function2_parameter2$ )

    uduavc_c$ = mid$( function2_parameter2$, uduavc_i, 1 )

    if ( asc( uduavc_c$ ) >= asc( "a" )) and ( asc( uduavc_c$ ) <= asc( "z" )) then

    uduavc_c$ = chr$( asc( "A" ) + ( asc( uduavc_c$ ) - asc( "a" )))

    end if

    uduavc_s$ = ( uduavc_s$ + uduavc_c$ )

    next uduavc_i

    print "parameter2$: " + chr$( 34 )+ uduavc_s$ + chr$( 34 )

    return



    MAIN:

    print "This program should print two strings, the second a capitalised copy of the first."

    fxqyrj_s$ = "Cower now brief mortals, for I am Death, 'gainst whom no lock will hold nor fastened portal bar"

    function2_parameter2$=fxqyrj_s$

    gosub function2

Outro

HEAVY METAL was developed on an Apple Power Macintosh 8100 in C++ compiled with Metrowerks CodeWarrior IDE 2.1 (Discover Programming Edition.)



et cetera
Follow

Get every new post delivered to your Inbox.