Objective-B3D

Blitz3D Forums/Blitz3D Programming/Objective-B3D

Yasha(Posted 2009) [#1]
Update 4/6/2010: Completely new (from scratch) version of Objective-B3D! Fixes several of the old version's problems. See post #17 (this first post will remain about the original version).


Warning! This will be a long post (and not very beginner-friendly)! I hope it's worth your time. Skip to the end for source code.

A couple of days ago, I was looking at the Wikipedia article on the C programming language, and discovered an interesting thing.


C++ and Objective-C were two different extensions of C that provided object-oriented capabilities. Both languages were originally implemented as source-to-source compilers -- source code was translated into C, and then compiled with a C compiler.
- Wikipedia



Huh. Apparently it's possible to implement OOP in an procedural language. Admittedly not news - assembly is procedural, after all - but not something one's used to thinking about. Perhaps it would be possible to write a preprocessor for an object-oriented dialect of Blitz3D that would output vanilla B3D source code?

Apparently so. And I have imaginatively named it Objective-B3D.

Before we continue I would like to point out that yes I do own BlitzMax and that this is, as everything I do seems to be, a largely academic exercise that just happens to also have some considerable practical potential. This was done for fun, intellectual exercise and to gain a better understanding of programming, not because I've never heard of miniB3D; please try to see it in that light.

To install Objective-B3D, download the binaries for the code processor and wrapper, or build them yourself from the source below. First, extract or build the code processor (that's the .bb code) to Blitz3D\bin\ObjB3D.exe . This is the part that translates OOP code into pure procedural code. Next, rename the existing blitzcc.exe to blitzcc_old.exe (it's very important that these are all named correctly, by the way). Finally, extract or build the wrapper exe (that's the .bmx code, or blitzcc_obj.exe in the archive) to Blitz3D\bin\blitzcc.exe (must be compiled as a console app). And you're away! I do recommend making a second Blitz3D installation, both for separate work on projects not requiring any of this stuff, and in case things go wrong.

The program itself consists of two entirely separate preprocessor stages (there's no requirement to use them together, actually - you might find one or the other more useful by itself): a vaguely C-like directive processor, and the Objective-B3D translator. I was originally going to include a third, to cover some functional programming elements, but decided against (the extreme popularity of my last attempt to integrate functional ideas leaves me thinking it wouldn't be worth the effort). Input is in the form of the file to process, optionally followed by " -d" to signify that debug mode is on. You can use it separately like this if you don't want to integrate it into the toolchain.

EDIT: Removed the C-like processor section, as it's not the real focus of this article. You can find it here if you need it.

The Blitz "Include" command is also processed in the first pass, in order to get everything at once.

But there is another, bigger part to this abomination...

Once the code has been processed once, it can be fed into the Objective-B3D translator. Objective-B3D can be considered an informal superset dialect of Blitz3D - there are a few new features, but all legal Blitz3D code (with a very few exceptions that won't affect most users, detailed below) should come out of this unchanged (except that the formatting will be ruined, but what can you do?). As the name and the previous sentence imply, my inspiration was taken not from C++, Java or BlitzMax (I do not in any way wish to compete with BlitzMax - please do not ban me!) but from Objective-C and SmallTalk, which operate a "purer" (more logical and internally consistent) kind of OOP, that will probably be completely unrecognisable to most people familiar with the dot-syntax used by C++/Java/BlitzMax.

Types (classes) are the core of object-orientation. Normal type declarations are perfectly valid in Objective-B3D, but you can also add a few things to the declaration:
Type MyType
	Field a
	Field b,charlie
	Private Field d$,e#
	Field g$[10]
	Public Field zz.MyType[10]
	Field d[8]
End Type

Type MyFinalType: MyType
	Private Field j$[10],x.MyType
End Type

The default state of all fields is, as usual in B3D, public. The Public modifier doesn't actually do anything, but you can safely put it there anyway if it makes things clearer. The Private modifier will make fields inaccessible from outside the class's own methods (actually it will just append two underscores in the final version, so if you really need to get at them anyway, you can use that, but consider a redesign). To extend a class, you can use a colon followed by the name of its superclass - this class will now have all of the fields above added to it, at the same access level they were declared at previously.

Some readers may be wondering where the methods are. As in Objective-C, the class interface (fields) and implementation (methods) are declared separately. Not strictly necessary, but it keeps things tidy.
;Arbitrarily ugly code for the purposes of illustration
Implement MyType
	Method Delete
		Local boogle.MyType
		Delete self
	End Method
	
	Method setA:value%
		a=value
	End Method
	
	Method getB
		Return b
	End Method
End Implement

Implement MyFinalType
	Method setA:value
		a=value+1
	End Method
	
	Method setX:newX.MyType
		x=newX
	End Method
	
	Method getX.MyType
		Return x.MyType
	End Method
End Implement

Methods are declared without parentheses and with a colon separating the name from the arguments, and each argument from the next (no optional arguments/default parameters). There is a reason for this - methods are not directly conceptually connected to functions in this style of OOP; rather, they are messages that request the object to perform an action. Methods are also inherited from the superclass, unless they are overridden by the subclass's own implementation (which must have the same number and type of arguments). It is important to note that there is NO REQUIREMENT for virtual/abstract methods, so don't implement anything you don't intend to use where it is. More on this below. You may make reference to "self" in methods if it makes you more comfortable, but don't attempt to redeclare it ("self" is a pointer to the object doing something, for those unfamiliar with OOP). You can reassign or delete it if you need to (be aware that it is an actual object variable, not an integer, so it is not polymorphic within the method body and is the only way to directly reference non-final objects).

"Getter" and "setter" methods are automatically generated for every public field (in the case of arrays, they have an "index" parameter as well). A "New" class method is automatically generated, as is a "Delete" method. You can safely override Delete if you want a custom destructor. Don't try to override New, though...

Class methods are declared the same way as instance methods, but with the extra keyword "Class" before "Method". They differ from instance methods in that their "self" variable actually points to the class object itself, not to an instance of that class. Using a class method is the only safe way to instatiate non-final classes - this is because, to facilitate polymorphism, ALL references to non-final classes are replaced with integer pointers. The only place nonfinal objects can be referenced directly is in their own methods (so implementing a constructor would require a call to class method New to be the recipient of an initialisation message).

Polymorphism should be a familiar topic in OOP. It behaves relatively as-expected in Objective-B3D, except that fields of non-final classes (ie. any polymorphic variable) may not be accessed directly (because they use integer pointers) - you have to use getter and setter methods. Rather more interesting is inheritance: because the idea of methods as function calls is replaced with messages to objects, there is no need for virtual methods to be declared - if the object in question implements the requested method, it will be found automatically; otherwise, nothing happens. This makes things a little more flexible than in other languages - not only do methods not need to exist, but the "method" part of a message might itself be the result of another function, as might the object (and since classes are also objects, even that can be changed at runtime).

Now for the part that people won't like: message syntax. To smooth things over, here's a translated version of one of John Judnich's examples in "Object-Oriented Programming in BlitzMax":
Type TRobot
	Field name$
	Field x#,y#
	Field health
End Type

Implement TRobot
	Method Move:newx#:newy#
		x=x+newx
		y=y+newy
	End Method
	
	Method Draw
		Color 255, 255, 255
		Text x - (Len(Name)/2), y - 20,Name
		Color 0, 0, 255
		Rect x - 5, y - 5, 10, 10
		Color 255, 0, 0
		Rect x - 4, y - 4, 8, 8
	End Method
End Implement

Graphics 640, 480,32,6
Local robot.TRobot = New TRobot
[:robot:SetName:"XB-75b"]
While Not KeyHit(1)
	Cls
	[:robot:Move:1:1]
	[:robot:Draw]
	Flip
Wend
End


Those who have used Objective-C will recognise the square-brackets, although there are more colons now, as I found the exact style used by Objective-C to be incompatible with the existing BASIC syntax. Square brackets surround a message, and every component of the message is preceded by a colon. The first field is the message recipient - either an object or a class (classes are also objects, but not many people will want to take advantage of this). You can also send a message to Null, but nothing will come of it. The second is the method selector; these two fields are obviously mandatory. Following this is the argument list (remember, no optional arguments - if there are too many or too few I have not bothered to define what will happen). Any field in this list may be a direct name, or it can be the result of a function or another message (yes, even the target and selector of a class method). However, if it is not possible for the type of arguments to be known at compile-time, you'll need to specify them or the runtime will assume they're integers, which may not be what you want. To specify type, simply add the type symbol (#, $, .mytype) at the end of the field, right before the following colon or closing bracket. Arguments are known at compile-time if both the target and selector are knowable, or if the target is a subtype of a polymorphic variable BUT the method was declared in the supertype (this is the only reason you'd need to declare virtual methods). In general, you can treat messages as expressions in the same way as function calls:
[: a : setA : [: b : getB ] ]
[: b : setA : [: a : getB ] ]
Print [: b : getB ]
Print [: a : getB ]
e = [:a:getB]
[: b : setA : d ]

[:PickClassAtRandom():DoSomethingToIt()]


Unlike in Objective-C, not all messages are late-bound: if the object and selector are both known at compile-time, the result will be a normal function call, and if one is known but not the other the resulting output code will still statically bind as much as possible, so there's no speed penalty for functionality you don't use.

I'll leave that there for now - hopefully people will ask questions if they are unclear on any element of this?

As mentioned above, there are a few areas where Objective-B3D code does not allow every element of Blitz3D code to compile as it otherwise would. As follows:

- Obviously Objective-B3D creates many helper functions, constants and classes. In general, all of their names end with two underscores, so I think it unlikely many people will have a problem here. If you also use two underscores at the end of any names, look through the source code for any conflicts.

- "Self" is used by methods to refer to their target (an object in the case of instance methods, or the class in the case of class methods). It's a hidden parameter that is the first in the argument list of the functions that methods are translated into. You cannot therefore declare a global variable named "Self" and expect this to work. It's bad practice to give a global a name like that anyway, so just don't do it.

- Blitz3D allows you to engage in the cardinal sin of declaring variables with the same name as a type. Objective-B3D will beat you to it - since each class is an object that can receive messages, there is a global object declared with the name of each type already. You really shouldn't be doing this, though ...because I said so.

EDIT: (this is, strictly speaking, a bug, not a feature) - The current incarnation of Objective-B3D will fail to correctly handle a global variable being declared and initialised on the same line (eg. "Global myGlobal = Something()" ). In the fullness of time this will be changed, but at the moment globals must have their declarations on completely separate lines - ie. "Global myGlobal <newline> myGlobal = Something()". Sorry about that.

Technically speaking, there are two more stages of preprocessing. The third stage is simply that an extra line is added at the top to Include "standard definitions" (class Type, box Types, box functions to allow strings and floats to be passed by Int pointer) - things that don't change. Nothing remarkable there. Finally, of course, there is compilation with blitzcc.exe.


EDIT: OK the source is waaaay too long for one post, so I'll post each file in its own box. Gimme a moment... sorry about that.


I make no guarantee that this program is bug-free - I lack the imagination to develop proper tests - and in fact there are almost certainly bugs there, so PLEASE report them if you find them and I will try to fix things.

Please consider this software public-domain. Thank you for your attention, and I hope at least someone finds it helpful or interesting.

EDIT 2: Just discovered that Noel beat me to this by five years or so... http://www.blitzbasic.com/codearcs/codearcs.php?code=1103 . Use that instead, he's a better coder than me.

Last edited 2010


Yasha(Posted 2009) [#2]
UPDATED - The main file (call it whatever you like):



Yasha(Posted 2009) [#3]
- "OO.bb"



Yasha(Posted 2009) [#4]
- "Lexer.bb"



Yasha(Posted 2009) [#5]
- "PPh.bb" (updated)



Yasha(Posted 2009) [#6]
- "StdDef.bb"


Sorry for the spamtastic posting.


D4NM4N(Posted 2009) [#7]
Interesting project, good luck with it. :)
(although i do have to ask the point when there is Bmax+b3dsdk/minib3d :/ )


_Skully(Posted 2009) [#8]
The point is that a donkey can mimic a horse

Wasn't that obvious?


xtremegamr(Posted 2009) [#9]
It sounds cool and all, but I have to agree with D4NM4N: is there really a point when there's Bmax?


Yasha(Posted 2009) [#10]
Well the point is that I for one find this kind of thing both fun and informative (no really - writing this is my idea of relaxation); I'm more interested in the theoretical aspects of programming than actually producing a game any time soon, so in order to fully understand OOP I decided it would be best to try and implement it myself, rather than just be spoonfed by Mark. Sure, if I want to actually use OO and Blitz together I'll go for BlitzMax over this mess every time, but that really isn't the goal here at all.

Not the usual point of view for this forum, I know, but different people get different things out of programming. I'm a real live CS student so don't expect anything approaching sanity from me...


_Skully(Posted 2009) [#11]
You should write a scripting language then... add whatever features you want...


Yasha(Posted 2009) [#12]
I started on one a while back (signature link) - actually about half of the above code (the directive preprocessor and the lexer) is ripped straight out of it with very little change. There are a couple of issues I haven't worked out yet (how to compile a switch/case with fallthrough?), but overall it's gone pretty well as well. Actually if I really needed to use OOP in Blitz3D I'd probably use that, since I imagine the necessary boxing/unboxing to allow native functions to receive different types of argument probably eats up any advantage of compiled over interpreted code (and yeah, extra features like "proper" recursion and a GC are always nice).


CodeGit(Posted 2009) [#13]
Why dont you write a parser that will take BLITZMAX code and create Objective-c code for the MAC. Now that would be extremely interesting. iPhone dev?????


Yasha(Posted 2009) [#14]
UPDATED! (Not because I think anyone cares, but because I don't like leaving public projects unfinished)

It's now possible to fully integrate Objective-B3D into the Blitz3D toolchain and use it from the IDE!

Of course, that's not the same as saying it actually works. The changes seem to have highlighted a few issues with the system as it is. For the time being, don't assign anything to Globals in the same line they're declared... will fix this sometime when I have energy...

While I'm pretty sure it's possible, using Kernel32.dll commands, to do this completely within Blitz3D, I couldn't be bothered to find out how to use them and instead used BlitzMax to interface with blitzcc.exe, because it passes a lot of information through the console and BlitzMax can do this; Blitz3D can't, without extensions. Do note that none of BlitzMax's features are being used to "cheat" in any way on the OOP side - all the mini-application does is provide a link between blitzcc and the code processor via the console.

Installation instructions are given above, and in the download (http://sites.google.com/site/quicknoodle/other-stuff). As above, I would strongly recommend you make a second installation of Blitz3D to try this out (and if you keep it, to separate objective and procedural projects). This is easier if you use IDEal, as it lets you choose a compiler on the main toolbar. (EDIT: Actually IDEal is weird, not sure this works with it... oh well.)

The code above is updated to reflect that it is now a "pure" code processor and not expected to interact with blitzcc.exe by itself in any way. Interacting with blitzcc is now handled by the ridiculously short BlitzMax app given here (must be compiled as a console app):


I was considering rewriting the whole thing in BlitzMax (it needs a complete rewrite anyway... it's a mess) but didn't really see the point (and that'd be too much like work).

Anyway, I hope this is at least useful to someone; failing that, I hope it's interesting or informative. Enjoy!


_PJ_(Posted 2009) [#15]

Well the point is that I for one find this kind of thing both fun and informative (no really - writing this is my idea of relaxation); I'm more interested in the theoretical aspects of programming than actually producing a game any time soon, so in order to fully understand OOP I decided it would be best to try and implement it myself, rather than just be spoonfed by Mark. Sure, if I want to actually use OO and Blitz together I'll go for BlitzMax over this mess every time, but that really isn't the goal here at all.




An interesting read, though I've dabbled in variations of C++ for scripting etc. I've not really had to deal with OOP and the programming I've done has always been rather procedural, so for me, I agree this is something of an aid to learning more on the OO front.


Mahan(Posted 2009) [#16]

(Not because I think anyone cares, ...)



I care!

I don't have the time to try out your work right now, that is one sad thing, but I highly appreciate your work here and will be delighted to try it out when I get back to my B3D project.

Do you happen to be INTP (I am)? I often find myself suggesting stuff to people and get an o.O-face back :-) I think what you did here is really cool work and the only thing holding it back from becoming main-stream in the blitz community is BlitzMax and its strong OOP support. That doesn't in any way mean that it's not useful though.

I was thinking in the preprocessor chains of thought a while back concerning B3D to add some kind of reflection or at least serialization support for types, and maybe that could be added somehow into your OOP preprocessor. I'll look into that when(if..) my commitment at work is lessened later on. (fulltime code- and specification-slave atm.).


Yasha(Posted 2010) [#17]
Time to flog a dead horse!

Objective-B3D has been completely rewritten from scratch. Click here to download! (Last updated April 2011)


The old version had three huge problems. Firstly, the message syntax was clunky: many people dislike Objective-C but this was even worse. Secondly, and more importantly, because it completely tore apart the project and reorganised it as a single file, the debugger and any error messages from B3D itself were next to useless and as a result error checking was very, very hard.

The new version has been designed to preserve line numbering, file structure, indentation and comments. As a result, although the code will of course look different it will still be recognisable in the debugger window! All lines are modified "in place" and saved to a file with a slightly decorated name; the "extra" functions needed to dispatch polymorphic calls etc. are all now outputted to a standard file ("objb3d_tmp.bb") - this file includes your project, so that it doesn't mess up the line numbering.

Thirdly, the syntax was totally incompatible with any existing Blitz IDEs. I have attempted to solve this by relying on a bare minimum of keywords (at some reduced functionality), so that the default B3D IDE will generally be fooled into accepting the code as legitimate. (IDEal is too clever to fool, sadly). My quick tests indicated that it will still work as part of the toolchain from the default IDE, but not from IDEal anyway.


Changes:

- Messaging rules: message selectors must now be a constant method name valid for the type receiving the message. This means that for polymorphism to work you will need to create an abstract method to inherit (there is no abstract marker... just create an empty method). Dynamic typing or dynamically selected methods are no longer allowed - this improves performance, and fits better with B3D's static/weak typing (I know it kinda detracts from the point of message passing vs. method calling, but it's more suited to the base language).

- Message syntax: methods are now called with the same syntax as Objective-C, except that parameters cannot be named. ie.:
[myObject myMessage :a :b :c ]


- Type syntax: as before, type blocks only describe instance variables, they can extend types with the colon operator, and fields can be marked as private (equivalent to C++/Java "protected") with Private. Public is no longer a keyword, and "super" is now a reserved field name (don't use it). eg.:
Type Animal
    Field name$
End Type

Type Dog : Animal
    Field waggingTail
    Private Field beenFed, beenWalked
End Type

Autogetters and setters are generated for all non-private fields, unless a method with the default name already exists (getters are just named the same as the field, while setters prepend "set", e.g. "setWaggingTail").

- Class Implementation syntax: this was a big mess before, especially because the IDE can't handle indented functions. Class implementation blocks are now begun and ended with special tags ";+ Class myClass" and ";+ End Class". These are not comments and if you want a comment on that line, you'll need a second semicolon. The choice to make them look like comments is to make them fit in more naturally with the way you might organise your code in a procedural project. Within each class block, functions are written normally (Function name(args) etc.) and instance variables are in scope (so "self" is reserved, and field names will point to the object field, not a local). Type definition blocks can appear in-or-outside class blocks (put them wherever you like!). eg.:
;+ Class Animal

Function Init(newName$)
    name = newName
End Function

;+ End Class

;+ Class Dog

Function Talk()
	Print name+"Arf! Arf!"
End Function

Class Function Create.Dog(newName$)
	Local d.Dog
	d=New Dog
	[d Init:newName]
	Return d
End Function

;+ End Class


- Polymorphism: You may not assign objects from variables of one type to another without an explicit cast - and the cast will fail without warning if it's not valid. This is because I didn't want to write a full B3D parser... you should consider redesigning whatever you're doing to use messages instead if this is a frequent issue. (Message recipients never need to be cast if the method is inherited.) eg.:
Local myAnimal.Animal = (Animal) New Dog
doSomethingToAnimal( (Animal) myDog )


- Field access: for the same reason, the only guaranteed place to access fields is within a method. In a function or the main program, trying to use \ to access inherited fields will fail, unfortunately. You should use getter and setter methods instead.

- The global type lists: A lot goes on behind the scenes; if you;re using inheritance, DO NOT rely on First/Last/Before/After to give you expected results, as they may return hidden instances that you didn't explicitly create (don't worry, New and Delete are overridden to cover this).

As before, double-underscore is used at the end of private names, so stay away from this and you should be fine. Reserved words are: Self, Super, Private, Class (...think that's all). Oh, and source files need to be in Windows format (CRLF line endings) - Unix or Mac format will break everything (if you don't know what this means, you don't need to do anything).

I haven't tested it thoroughly, but the supplied examples work correctly and it does successfully integrate into the toolchain using the default IDE.

Enjoy!


Disclaimer: As before, this work was undertaken for my own amusement and that of others only. It is not intended as a serious development solution, or to compete with any BRL products. I consider "addressing usability issues" to be part of the fun of making it, and do not seriously expect anyone to actually use this tool.

Last edited 2011


_PJ_(Posted 2010) [#18]
Really impressive, Yasha!

I've only just gooten back to see this, but will have a proper 'fiddle around' with it over the week :)

I think I can seriously make some use of this!


Almo(Posted 2010) [#19]
Just want to say that's really cool!


Bobysait(Posted 2011) [#20]
Nice job BUT :

Are you sure you're allowed to publish original "blitzcc.exe" compiler in your archive ?
I'm almost sure it is really forbiden as you can pass it any text file you want to run blitz3d (and you always should have a valid license of blitz3d to do that)


ps : I made about the same to achieve OO in blitz3d and got the same problem with IDeal ... really disturbing

Last edited 2011


Yasha(Posted 2011) [#21]
Oh wow someone looked at this!

Are you sure you're allowed to publish original "blitzcc.exe" compiler in your archive ?


It's not the original blitzcc.exe - it's just a tiny wrapper program that calls Objective-B3D and regular-B3D in order on the source. You have to supply the original blitzcc yourself (the idea is that if the wrapper program is renamed to blitzcc.exe, programs that originally looked for Blitz3D now get this program).

The reason there are two exes is because the preprocessor (the larger one) is separate from the wrapper, and is supposed to be able to stand alone.


Anyway, don't pay too much attention to this project. It's still got too many bugs to be usable, sadly (actually I did use a cut-down version of it for some commercial code, because it sped up writing boilerplate... but the method syntax doesn't work properly).

Its successor will be along soon - a real compiler this time, not a B3D-source-generator. Enhanced version of the object system, as well as an aspect system and some other cool stuff (yay, "subject oriented programming"!).


Bobysait(Posted 2011) [#22]
It's not the original blitzcc.exe - it's just a tiny wrapper program that calls Objective-B3D and regular-B3D

Ok, so it's just a mistake from me
I just have modified the blitzcc with yours (as mentioned in instructions) and I didn't remember, so I did it once again, then they were both (blitzcc and blitzcc_old) the exact same size, then I thought you released the original blitzcc :)
happy I've got a backup from blitzcc in an other folder, cause I've overwriten the one from the bin folder >.<

whatever
Anyway, don't pay too much attention to this project. It's still got too many bugs to be usable, sadly (actually I did use a cut-down version of it for some commercial code, because it sped up writing boilerplate... but the method syntax doesn't work properly).

Don't worry, I just looked for "Fun", it's always interesting to run other stuff like this
I already have made my own blitzlike compiler, I found yours very instructive
and it might get me some new ideas ;)

Last edited 2011


Yue(Posted 2011) [#23]
I enterame that's the thing, but the google translator sucks, does not help me.


eNano(Posted 2015) [#24]
Hi Yasha as a newbie I find this absolutely awesome!, I'm learning to code graphics really slowly and adding complexity to a language like blitz3d helps me a lot to understand some concepts.

I have 3 questions:

Is this code safe to use in standard projects like a simple fps or with userlibs like fastlibs and pointers and that stuffs?

Should this work in Ideal IDE without problem?

Do I loose some speed in my projects using this?

I really thanks you for sharing all this stuffs!!


Yasha(Posted 2015) [#25]
No, this code is not safe to use in practice. As I touched on above, it actually emits buggy generated code. I don't think this can actually be of any practical use to someone who isn't deeply familiar with it and able to hand-patch code as they go (which is what I did on the one project where I used it). It also didn't work with IDEal.

I wrote this back before I bothered to learn how to write parsers/compilers properly. As a result it's a complete mess and would have to be redesigned (again) from the ground up (even if I hadn't completely forgotten about it or how it works!).

There is a minor speed hit to the generated code but unless you go completely crazy with objects, it's nothing major (and probably the equivalent of what you;d have to do to get polymorphic behaviour anyway).

I'm honoured by your interest in the project, but it's really not complete or usable as it is. I wouldn't bother with it if I were you. (If you really want to learn, you might even do better to recreate it yourself without looking at this version.)


If there's genuine interest in using a language like this one I might rewrite it fully sometime in the future (now that B3D is open-source, it could be a complete standalone project). But I think you'd find BlitzMax more appealing.


eNano(Posted 2015) [#26]
Thanks a lot for your answer I guess I could try what you suggest. I just found blitz3d an amazing lightweight and simple tool for prototyping 3d applications for people like me who only had time to learn Basic. I still find some concepts really abstract in more powerful programs like blitzmax but I guess I will have to take a deeper look it.
If you have time to play with this in the future you will make a lot of newbies really happy :)