Project Updates

Tuesday, February 1, 2011

On documenting the engine

I decided that it would be a good idea to not document the engine with the widespread approach of simply documenting the API, and explaining things piecemeal.  Almost always that stuff is generated from big clunky interleaved function comments that dwarf the code itself and are really painful to read.  There are two short-term reasons I don't want to do it this way.

  1. The text editor TextPad can't handle separate docs, I am working with dumb flat text files for the time being, and I really don't want to clutter things up with interleaved doc comments.
  2. I never liked API documentation.  They focus on what functions do, and not how to use them or what they mean in the big picture.
Instead, I think that this will be my approach for now ...
  1. Explain the framework in detail; this part doesn't change anymore, so this will be like the "key" to the whole rest of the system.
  2. Make the code more self-documenting, with stack comments everywhere except where it would be ridiculously obvious or obtrusive, and explain in comments only important things.  Make formatting consistent so simple stack-comment-only glossaries could be generated automatically.
  3. Explain things from a bird's eye view in a way that describes the design so you know what you can do with it and where to find what you need.
  4. Make glossaries for interfaces.  This part is relatively fixed.
  5. Make a cookbook of mini-tutorials for common stuff everyone would want to do.  Deprecate/rewrite tutorials when/if API changes make them outdated.
Subject to revision, but I think I will give it a try and see how it goes.

Saturday, January 29, 2011

Added shared members

Finally got around to adding this feature which will eliminate an ugly hack in iEntity.f, and I think actually eliminate iEntity altogether?  (Well, we'll see.)

Shared members allow one object to share properties with another one, so that they appear to be properties of the sharee, but they really are the sharer's.

The way it turned out to be implemented was surprisingly elegant.

To use it, you create a special property called a "reference" with the word "Via".

Example:

Module Entity
Via Owner

This makes a field called Owner for Entity that works like any other property.  There is nothing special about it by itself.  But now, all subsequent fields will become shared fields using that reference Owner.

Vector Make Pos
Var Visible
...
(And so on.  To get out of that mode, you'd call Static, Embedded, or Global)

So now, instead of pointing to This like most fields, Pos and Visible would go through the address pointed to by Owner.  To use them, you have to set Owner to something before doing anything.  This might be made automatic for the sharer sometime, but for now, you have to set it manually in both constructors.

To share those fields, here's what you'd do:

Component MyComponent  \ As an example, we're using a component, but you can do it with any Structure or Module too.
Using Entity Share Owner

Actually, Component will define its own Owner automatically, but for the sake of this example we're making it explicit.

First we call Using to add Entity's words to MyComponent's included classes.  Then we say we want to share properties associated with the Owner reference.  (What's kind of cute is that Share is nothing but an alias for Var.)  So now, the Owner's Pos and Visible can be called from MyComponent's functions as if they were part of MyComponent.  Even >Pos and >Visible work.

What's great about the implementation is references don't have to be properties of classes; they can be static, or even global.  All the shared properties do is evaluate "Owner @" and then the property as normal.  You can connect lots of interdependent objects without explicit coupling throughout the code; the connection is implicit and defined in one place.

Thursday, January 13, 2011

Shmup demo!

Here is a tech demo made out of one of the test programs I wrote for the shmup game.
A to shoot
Download

Sunday, January 9, 2011

New OOP Syntax Details

From the Syntax2.f file:

Module
   removes all modules from the search order
   creates the structure, creates a wordlist, and sets the pointer to the size counter for field words
   it doesn't add itself to the search order automatically

::
   Compile a verb or method
   If the word that follows is NOT a method ,
      creates an internal word that can be accessed externally with a > prefix
      both words it creates are private; to use them you have to add the module to the search order with Using
   If the word that follows IS a method ,
      it sets the following code to be the implementation for that method with this module.
      and it creates a version using the Module:Method convention (called the direct version)
         unlike methods, direct versions they are always internal.
      Methods are still always public, including the direct versions.

Fields are always private now.  They still have the internal and external versions, but you have to add the class to the search order with Using or :: to get to them.

Procedural
   Remove all classes from the search order.

Var
   now a shorthand for Variable but also supporting being a cell-size field
   in a Module , fields are private.
   in a Structure , fields are public.

Field and Make can also be used inside or outside a class.

Embedded
   automatically called by Module (and Structure) , puts Var and friends
   in "OOP" mode, i.e. they will be private or public depending on if
   we're defining a module or a structure.

Make: and New
   Automatic initialization; note this doesn't preclude the Class: convention
   Make: ;  is used to either embed a module into a class or
      compile a module into the dictionary using *STATIC* parameters.
      When a Module is instantiated, even if it's embedded
      will be passed to that module's Init method.
   'New' is the runtime version of the same principle. It passes whatever
      parameters to the given Module's implementation of Init .

Friday, January 7, 2011

Introducing an improved syntax for the OOP component

Introducing a improved syntax for the OOP component. It's a slight modification to what's currently in place, that'll hopefully be easier to work with and more logical. Trying to go for Zero-Context, that is, code whose location doesn't depend so much on the current state of the compiler.  Hoping it'll encourage more interactive development, less recompilation from the beginning.  Somewhat counter-intuitively, it locks everything but methods away privately to each class.  However it is very easy to "include" them into the domains of the current class, or "open" them in what I call Procedural Mode, both using the Using keyword.  I've adapted 3 classes to it and it seems to be working - but I'm about to try to playing with it some in the IDE to see if it fulfills its purpose.

Thursday, January 6, 2011

Great minds think alike.

TIL that this guy had proposed an object oriented extension to Forth that almost mirrors the one I designed for Tengoku.  In 1996.  That's 15 years ago now. :)  Anyway it's so close it mirrors some of the semantics - Field , Method , and even { and } (which are sort of being phased out and replaced though by As , With , and the > prefix).

Link to the proposal document:
http://www.forth.org/literature/oopf.html

Also, I just found and will purchase this book: Object-Oriented Forth.  Published in 1987!

http://search.barnesandnoble.com/books/product.aspx?r=1&r=1&IF=N&ISBN=0125635702&cm_mmc=Goodreads-_-k117601-_-j12871747k117601-_-Primary

On the coding front, I cleaned up the source code, and thinking I should probably do a little more.  Going through the hedges with the clippers.  :)  Maybe a bit like Edward Scissorhands.  :)  It's really satisfying.  Besides making it nice and pretty and clean, helps put the different components in perspective.

There is a lot of code and so much of it still shows residual signs of the confused, disorganized thinking process I was going through just to figure out what low level services worked well.  I wish I had known at the beginning what I've accumulated through the process, but that's sort of a self contradicting statement.

I've got a pretty nice set of reliable services now, but there is just such a multitude of more stuff I want to do.  Really made me realize how much progress has been made and continues to be made in the "Outside World".  I'm playing a weird game of catchup.  I want power, but I don't trust the tools that are available.  Maybe now is time to stop "fortifying" for a moment and adopt a new groove of finishing products that add a few new features at a time.

The shmup performs pretty well on an aging 2005 lappy.  3000+ colliding bullets at 60hz with plenty of CPU to spare.  Slowdown doesn't really impact smoothness much anyway though thanks to fixed timestep.  It's implemented using a special module, the BulletMngr, that brings together a Spritebatch and a Collisiongrid and some other things but doesn't use entities because those are too slow for that many moving things.  The majority of the time is spent drawing the bullets.  A clever sprite-generating vertex shader would virtually eliminate any limit on sprite count.  I like having the ability to have tons of sprites.  The game isn't going to expect you to actually dodge 3000 though, exactly. :)

Really annoyed at the laptop though.  It says it supports fragment (pixel) shaders but it actually doesn't!  Witnessed this with 3dMark '06 and firsthand saw the driver spit back "can't link fragment shader" / "fragment shader not supported by HW" etc.   So I can't develop post effects on it. :( The desktop works great though.

Actually, on the shader front, I think I did something that was really cool the other day - I implemented a floating-point framebuffer and an HDR shader that dithers the output, so you eliminate banding and can fake really, really subtle color degradations, especially in the lower luminance levels.  It was very gratifying because here I've got the full spectrum of fidelity - I can do 8-bit pixely sprites (the default texture filtering is GL_NEAREST :) or I can render really smooth, anti-aliased geometry or bitmaps and do extremely smooth post effects with perceptually infinite color range.  Isn't that nice?  I think so.
 
Kind of afraid to just jump in and play with the engine still - it has trained me to think it could break at any moment - I think I'd rather work on the game idea so there is less unknown when I sit down to "implement" (in Forth implementing is ALWAYS experimentation though, ain't that nice ;).  Inevitably I will want to redesign some feature or two or three to suit the game.  But I think I've coded things in a modular enough way (hence putting almost everything, literally, in "modules") that I won't be running back to the starting line, and I have lots of reusable pieces that I really like as they are.