Smart Mobile Studio
  • News
  • Forums
  • Download
  • Store
  • Showcases
    • Featured demos
    • The Smart Contest 2013, Round 1 – Graphics
  • Documentation
    • Get the book
    • System requirements
    • Prerequisites
    • Getting started
      • Introduction
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • Themes and styles
    • Project types
      • Visual project
      • Game project
      • Console project
    • Layout manager
    • Networking
      • TW3HttpRequest
      • TW3JSONP
      • Loading files
  • About

Author Archives: Jon Lennart

Ghost polygon, back to the 90s

Posted on 04.02.2012 by Jon Lennart Posted in Documentation
Spaceballs

Spaceballs

In this little tutorial we are going to take a trip back in time, back to the golden age of personal computing. A time when the ultimate computer was the Commodore Amiga and the latest kid on the block was wire-frame 3d graphics and polygon art. I am of course talking about the 1990’s and the glowing polygon effect.
Continue reading→

graphics tutorial

Working with javascript structures

Posted on 04.02.2012 by Jon Lennart Posted in Documentation 4 Comments

When interacting with ordinary javascript libraries or a remote webservice you natually have to go native with your datastructures. Under Smart this can be handled in a variety of ways but the two most common approaches are to either use a record or a variant.

Using records

Records in Smart work just like they do in other object pascal environments. And since Smart compiles to javascript rather than machine opcodes, a record will always compile to an ordinary javascript structure. I should note that javascript really doesnt distinguish between what we would call a record and objects. In javascript everything is an object.

So the following object pascal code:

[sourcecode language=”delphi”]
type TMyInfo = Record
miName: String;
miAge: Integer;
miGender: integer;
End;
[/sourcecode]

Results in the following predictable javascript code:

[sourcecode language=”javascript”]
{
miName: "",
miAge: 0,
miGender: 0
}
[/sourcecode]

This means that when you want to interact with native javascript libraries that expects a structure of values, you can use records to match it directly.

Variants

Using variants to achieve the same thing is perhaps easier, especially since you dont have to predefine the structure by hand. As of writing however it does require you to initialize the variant manually. We will probably add some RTL functions to simplify this very soon, but for now you can use this “one liner” ASM snippet:

[sourcecode language=”delphi”]
Procedure testvariant;
var
mData: variant;
Begin
asm @mData = {}; end; // Set variant to "empty JS object"
mData.miName:=’john doe’;
mData.miAge:=39;
mData.miGender:=1;
end;
[/sourcecode]

The resulting javascript structure will be exactly the same as that produced by the record. One difference to keep in mind though, is that the compiler will output the names “as is”. There is no way for Smart to map the content of a native object so make sure you get the names right.

Another article about Smart

Posted on 03.02.2012 by Jon Lennart Posted in News

Pascal Game Developer has a nice article about Smart Mobile Studio. Visit their website and have a look: http://www.pascalgamedevelopment.com/

Thinking ahead

Posted on 01.02.2012 by Jon Lennart Posted in Developers log 3 Comments

I have to come up with some names for the different technologies soon. Smart now have two terms for compiler and also two levels of RTL: the low level RTL that is a part of Eric’s compiler, and a high level RTL which is our “VCL” clone. Im thinking of naming our component library the VJL (visual javascript library), and instead of refering to the compiler infrastructure as “the compiler”, it is more fitting to call it “the build tool”.

One vs. many

As the test group knows, the build-tool takes your source-code, invoked the compiler and finally glues everything together into a final, solid HTML5 document. Since our system was originally designed for iOS development only, and since Smart components (including forms, which is our version of pages in a way) are purely javascript based – a fully operational “app” really only needs one HTML file.

In Alpha 2 i removed the injection of code directly into the document.body section and introduced “Application.Display.View” to the VJL. The reason for this was make the application regard “the screen” abstractly. So by altering what “display.view” points to – you can make your apps live inside any DIV you wish.

A couple of testers have reported back that it could be handy to separate the RTL from the program code. There are a number of scenarios where you might, for example, want to run multiple Smart apps on the same document. If you run a website and want to get rid of Flash for instance, it would be nice to code the new banner in Smart and also host a game or a cool menu written in Smart as well.

Having talked it over with Eric it became clear that this should be reasonable to achieve, but it will come at a price: namely that it defeats the latest compiler switch named “smart linking”. When you smart link your apps, only the code you have used is included in the final binary (in our case “binary” is javascript). It’s the same technique Delphi and C++ uses to make programs as small as possible.

So if we include the feature then it will disable the smart linking option. I am experimenting with this now, by dumping the entire RTL into a separate file. If it doesn’t produce any negative side effects (except a small speed penalty and some bloat) then I’ll include it as an option. Eric might slap me over the head for playing around with this – but it would (in my view) complete the parallel of “Delphi” for javascript.

Reusable libraries

One of my long term goals is to add a new project type to Smart for writing libraries. Which would be the javascript incarnation of DLL’s. Since we have our own IDE we could generate a class-map for the library – which you could then import later so the Smart IDE can keep track of what the libraries export. A bit like a Windows TLB file when working with COM objects.

We should be able to poll this off by isolating the compiled code in it’s own name-space. It would then have it’s own RTL and library – but due to the nature of Javascript, it should actually work 🙂 It would mean a little tweak to the RTL but we are constantly tweaking anyhow.

Why are libraries important? Components, that’s why. By pre-compiling and obfuscating your code – you could write and sell your own components. The other benefits are self evident I think.

Tired of handcrafting your Javascript apps?

Posted on 01.02.2012 by Jon Lennart Posted in News and articles

Before we started developing Smart Mobile Studio we did a survey of the alternatives for developing mobile apps. That’s actually where the initial idea and motivation came from. During this survey we must have tested at least 14 different “app” machines, languages and “rapid” development environments. We tested the serious players like C++, object pascal, C# and Java – to the outright scams which usually include the phrase “create your app in a day” (but the app you get is just a template with no real value what so ever).

The result of our survey was disappointing to say the least. At the time, using Free-pascal to work with iOS was a bit of a black art so while that was our initial choice – any substantial information regarding cross compilation was virtually non existent, so we decided to go for C# in developing our iOS apps. This involved learning a new language, a new platform and to some extent a whole new way of thinking.

But one thing we did notice was that Javascript had come a long way. While all the native systems were struggling to get aboard the iOS and Android bandwagon – javascript was all over the place. Doing things it’s not supposed to do in classical terms. Everything from silky smooth animations to action packed platform games.

This is a snapshot from a game written in BlitzBasic which demonstrates what modern Javascript can do. We are old fans of Mark Sibly at Optimale Systemer!

Javascript can now do amazing things

To make a long story short we continued working in C# and object pascal, but as the idea behind cross compilation and using javascript as a medium began to grow, we found ourselves seeking out like-minded people, putting our ideas to the test. Unlike the “app machines” however, we did it properly from the ground up.

So the question is not if javascript works. The question is how to use that power properly.

Working with ordinary web technologies

When we took the time to look at javascript with new eyes, three things became apparent. First, browsers are not just page readers anymore but rather fully fledged multimedia environments. Secondly, Javascript has grown and can make use of the browser in a whole new way. And last but not least: javascript’s lack of structure is both it’s strength and it’s downfall.

Take something simple like a visual component. When you dig into the complexities of this simple task it turns out it’s not that simple after all. As of writing there exist no single standard between the different javascript frameworks on the marked. It is also highly unlikely that it ever will – because it’s not financially beneficial for these companies to work together. They would lose their uniqueness if they did, not to mention the technical difficulties getting two javascript frameworks talking to each other. When you use a framework you stick to it, mixing two different systems could in theory work – but in real life it quickly becomes a mess.

Classic remake of capcom streetfighter using gameQuery JS framework

Classic remake of capcom streetfighter using gameQuery JS framework

Encapsulation and portability of source is also an issue, not in terms of browser compatibility – but in terms of programmers sharing solutions. There are several ways a javascript developer can create the same thing – and the lack of a common approach (which classical languages solve by syntax, classes and a common foundation like the VCL) makes it extremely time consuming.

After we created a small demo/game in Javascript, testing out ideas and playing around with the multimedia features, it became crystal clear that it simply takes to much time to hand-craft large projects in javascript. You can use one of the many ready-made frameworks out there, but the amount of source code you need to write for a large game or application is ridicules.

So what is the alternative?

HTML5The alternative is not to ignore javascript, but rather to use javascript as a medium. What we did with Smart Mobile Studio was to transform a disadvantage into an asset. Javascript is the proverbial “wax that takes many forms”. We projected the rigid and time proven structure of object pascal onto the “everything goes” landscape of javascript. The end result is that you can now use the power of object pascal, it’s encapsulation, it’s class hierarchy, it’s true object inheritance and (thanks to our super clever compiler guru Eric Grange) even fancy concepts like interfaces, closures and var parameters. So not only do you get the power of javascript – you also gain the wisdom and experience of more than 18 years of pascal evolution (not to mention the object pascal community which is a living genius factory).

With a few hundred lines of pascal code you can achieve what it would require thousands – if not tens of thousands lines of javascript to match. But the central strength of pascal is that of scope and size. A large object pascal code-base can be maintained due to the architecture of the language. The same project in “native” javascript terms would be nearly impossible to keep track of. The time and cost involved in developing and maintaining a 200.000 lines long javascript project cannot be justified when you can achieve the same with 20.000 lines of pascal. Object pascal was designed to handle large projects. Javascript was not.

So. Are you tired of spending days hand-crafting javascript that could be delivered in hours?

javascript Pascal Smart Mobile Studio

Taking advantage of classical programming

Posted on 31.01.2012 by Jon Lennart Posted in News and articles
10.000 lines of javascript can be hard to maintain

Javascript can be hard to maintain

Let’s face it, Javascript is both a powerful and flexible language, but developing and maintaining large scale projects in a dialect not really designed for it is frustrating. The reason javascript libraries like jQuery, jQTouch and Sencha have remained more or less unrivaled for years now – is first and foremost because of the monumental effort involved.

The key factor itself have to do with the actual language. Javascript is a fantastic language, but sadly it lacks many of the traditional programming concepts native to languages like C++ and object pascal. Concepts like classes, true object inheritance, interfaces and type casting – techniques and technology created exactly for the purpose of making large frameworks manageable and robust.

Changing the game

With Smart Mobile Studio however you can take full advantage of these classical concepts. This is because our product allows you to write ordinary, classical object pascal (made famous by Delphi, Free-pascal or other incarnations of the language) and it’s instantly converted into super charged javascript.

The compiler at the heart of Smart generates javascript in a way that implements all the aforementioned technologies. So even if javascript itself doesn’t support concepts like interfaces, it is crafted by the compiler in javascript itself. And if you are worrying about speed – you will find that even with all these powerful and classical technologies – Smart Mobile Studio can run with the best of them. To make it plain: Smart does for the browser what Delphi did for the Windows platform.

You also get an IDE (integrated development environment) specifically designed for Smart programming

Write pascal, compile to javascript

Write pascal, compile to javascript

Easy to use, easy to learn and very rewarding

If you haven’t used pascal before then don’t worry. It was designed to be taught in school to students of object oriented software development. Chances are you have already used it yourself or have heard about Delphi or Free-pascal from a co-worker. Object pascal is responsible for hundreds of thousands of applications in the Windows world – and it’s still knocking out killer apps today.

Easy to use doesn’t make it a lightweight in terms of features however. Object pascal is fast, dynamic, robust and can do pretty much everything C++ can do.

With Smart you can now take your knowledge of classical programming one step further – into the domain of super fast HTML5 web applications. You can also use third party products like Phonegap and compile your generated web app into a real, binary executable program – ready for app-store. In fact, only hours after Smart was released to it’s testers, demo projects made it’s way onto the Android marketplace (!)

So what would you rather maintain? 10.000 lines of javascript code or 1000 lines of pascal code to achieve the same thing? Object pascal is a proven, tested by time and established language designed to handle large scale projects. Javascript is not. The benefits of using a compiler that generates javascript are just to great to ignore.

HTML5 javascript Pascal Smart Mobile Studio

All new Smart Mobile Studio

Posted on 23.01.2012 by Jon Lennart Posted in Developers log 4 Comments

For the past week and a half things have been quite calm on our website, this is not due to lack of work but rather focusing on some of the more tricky aspects of the IDE. So here they are in no particular order:

Alternative rendering

As an alternative to Chromium I attempted to wrap the Opera DLL’s last weekend, but the differences between Safari and Opera (both style and javascript wise) were to large – so I decided to drop it. Chrome is the browser most compatible with Safari (they both use the same webkit foundation) and as such we will stick with TChromium. We also had to backtrack to find the most stable version of TChromium since the latest revisions simply don’t work as expected.

Keyword proposal

Keyword proposal now works as expected

Keyword proposal now works as expected

This is an issue that has been driving me nuts for a while, but finally I tracked down the bug (wrong cache pointer .. sigh) – and Smart Mobile Studio now have keyword proposal in the box. We will naturally aim to expand this into the realm of code-completion and other advanced features in the future.

XML file format

In the first versions of the Alpha release we used a custom binary file format. This file format is now replaced by a proper XML format, making it easier to expand the system with new options and data without breaking backwards compatibility. You will need to copy and paste out your units to make the transition though, but it’s a small price to pay for a more versatile system. The new file format also supports external unit files (much like Delphi has by default) and we added a recursive search method to locate implicitly referenced units. Also, a new folder as been added to the mix: “libraries”. If you have made some utility units place those files under IDE/Libraries and the IDE will automatically find them.

What’s next

Once we have completed some of the tickets on fogbugz the final battle begins, namely offscreen rendering of components and the visual form designer. Then we brush up on the look & feel of the IDE and give the standard components more features and bling — then it’s release time.

Crack open the Redbull, im ready to rock 🙂

Variant is your friend

Posted on 12.01.2012 by Jon Lennart Posted in Developers log

Using variants as mediators is now possible under Smart Mobile Studio. This removes some of the burden when interacting with native javascript objects or external libraries:

[sourcecode language=”delphi”]
procedure TMyObject.InvokeByVariant;
var
mSrc: variant;
Begin
//get the browsers window object
asm
@mSrc = window;
end;

//invoke our method
handleCallback(mSrc);
end;

procedure TMyObject.HandleCallback(a:variant);
Begin
// treat "a" as an object
a.alert(‘this is a test’);
end;
[/sourcecode]

Note: Variants are treated as “unknown” by the codegen. It has no compiler operators for it, meaning you cant write “if a<>1 then” or “a:=12”. Variants are primarily used to transport native values and objects between methods dealing with javascript objects or browser objects.

In the above example we simply calls a procedure passing the native browser object “window” as a parameter. In the HandleCallBack method we invoke the alert method of that object. Once again, Smart deals with variants as unknown entities – so there is no checking that “alert” actually exists.

Files, folders and the dreaded javascript filesystem

Posted on 11.01.2012 by Jon Lennart Posted in Developers log
Javascript filesystem is bonkers

The collective wisdom of the WC3 can be questioned from time to time.

One of the trickiest and most frustrating aspects of javascript coding has to be the async file-system. Where opening a file and looping through a read sequence sounds easy enough (and is in most languages) – being async means that everything is handled through events. Why you say? Because javascript is by nature single threaded, so the cpu time has to be divided between all the action that takes place inside the browser. And that includes accessing files and folders.

In short, when you open the filesystem – the actual object you get back is delivered through an event. When you want to read X number of bytes from a file, you invoke it in one place and handle the actual reading someplace else. So it’s not exactly linear and object pascal friendly to say the least.

Using the force, Sith style

To solve this I have come up with the concept of disk actions. A disk action in this case is basically an object that handles everything associated with the action you want to execute (loadfile, savefile, copy etc.) – this gives us the benefit of isolating the code that invokes the filesystem and it’s event handler(s) in one place. And those that want to access the filesystem through Smart Mobile Studio wont have to deal with the ridicules visions of the World Wide Web Consortium (WC3).

My wrapper aims at handling things like this:

[sourcecode language=”delphi”]
FFileSystem:=TW3FileSystem.Create;
try
FFileSystem.open(5 * CNT_MEGABYTE,fstPersistent);
try
FFileSystem.Execute(TW3OpenFileAction.Create
(‘prefs.ini’,IniFileRead);
finally
FFileSystem.close;
end;
finally
FFileSystem.free;
end;

Procedure IniFileRead(sender:TObject;aData:TW3Buffer;
aFilename:String);
Begin
//File is read into a buffer (actually a "blob"
//Use the methods of TW3Buffer and TW3View(ers) to
//access the data in "reader" style
w3_showmessage(aData.toString);
end;
[/sourcecode]

Always been more of an empire man

Always been more of an empire man

But due to the nature of the javascript callback system, we probably have to move several aspects of the above into events. But at least I will isolate the events in one object, making it a hell of a lot easier to work with than native javascript.

For example, “FFileSystem.Execute” wont be a legal call in the above example, because it will be executed before the event which delivers the file-system native object has called us back. To solve this I have some tricks up my sleeve – but I think it’s wise to play it safe when it comes to building a new RTL from scratch. So expect some event management.

The answere is 42

I also built in a fail-safe for error codes. As I was testing the same code in both Chrome, Safari and FireFox – i noticed that the error codes where different between two browsers (which shall remain anonymous but involves a fox and some iron). The error names were the same (e.g: FileError.QUOTA_EXCEEDED_ERR) but the integer values could differ.

So instead of just hard-coding the numbers I used the newly added TW3Dictionary object(s) to map the error codes in the browser to it’s Object Pascal type enumeration. So even if the browser alters the actual error code our code will work just fine.

[sourcecode language=”delphi”]
//Register known errors in the constructor
FErrors:=TW3IntDictionary.Create;
registerError(fseQuotaExceeded);
registerError(fseNotFound);
registerError(fseSecurity);
registerError(fseInvalidModification);
registerError(fseInvalidState);
registerError(fseUnknown);

//Do evil things with butter
Procedure TW3FileSystem.RegisterError(aKind:TW3FileSystemError);
var
mKey: String;
Begin
if supported then
Begin
try
mKey:=IntToStr(ErrorToNative(aKind));
FErrors.Values[mKey]:=ord(aKind);
except
on e: exception do
Raise EW3Exception.CreateFmt(CNT_ERR_METHOD,
[‘RegisterError’,ClassName,e.message]);
end;
end;
end;
[/sourcecode]

Thank god I only have the audio and video objects left to wrap, because I’m getting a bit tired of low level javascript. But the foundation is getting tweaked and polished (Primoz Gabrijelcic have really given it a run for it’s money, testing every avenue and tidbit in the framework. I dont think I have ever seen a person consume and adapt to information that fast. Also the wizard of code which is Eric Grange is ever watchfull and actually knocked out a full game in under a day after release), so when the foundation is done for version 1.0 –  I can fully dedicate myself to high-level component writing.

Having said that — there is plenty of room for you guys to create your own units and start creating components for Smart Mobile Studio!

So far people have created games, advanced mandelbrot explorers, particle systems, hacker group demos and even classes that connect directly to RemObjects services (!) – and we aren’t even out of the alpha phase. Imagine what version 2.0 will look like. Buckle up dorothy because we’re just getting started (!)

Oh almost forgot.. Whenever I have the spare time, I will be implementing a converter for .mod music files (sound-tracker, pro-tracker: those old sample based music files). Im not sure the JS timer system is up for the challenge, perhaps we have to use web-workers (threads) to handle the dispatching – but I really want to add the frosting on the cake later on. No one has ever done anything like this in Javascript – so why not send a spartan to do it 😉

Fair play

And please. Try to avoid copying software. We are a two man company and have dedicated a lot of resources to polling this off. If you use it in some way – please support our work and buy a license when it’s released. If you want your friend to try it out then just ask us and he can register with the alpha team. We hear code written in Smart is already being used in production scenarios, and it’s sort of self-defeating for the community if what we hear is true.

Our prices will be very reasonable. Somewhere between $200 – $400 for the first version which is very humble concidering 6+ months of work has gone into research, figuring out how to do things, building a model and bridging technologies.

Smart Mobile Studio is becoming a weapon of mass construction – ok so let’s show those javascript punters what were made of 🙂

How do i move graphics from the canvas to an image?

Posted on 10.01.2012 by Jon Lennart Posted in Documentation
Generating images offscreen and using it is now a snap!

Generating images offscreen and using it is now a snap!

In alpha release 3 several missing bits and pieces from the HTML5 standard was added to Smart Mobile Studio. One of the key methods that were missing from our canvas implementation was toDataUrl – a function which has it’s opposite in TW3ControlBackground and TW3Image fromURL and LoadFromUrl methods.

So in effect, it is now very simple to transport off-screen graphics (graphics you have created on a canvas) and use it as either a background or as the content of a normal image.

Here is an quick example of how to create a picture dynamically and display it in a TW3Image control. Also notice that you can actually assign the image to the background of any TW3CustomControl descendant.

To run the example create a new visual project and replace the code in Form1 with the following:

[sourcecode language=”delphi”]
unit Form1;

interface

uses w3system, w3ctrls, w3forms, w3graphics,w3application;

type

TForm1=class(TW3form)
private
{ Private methods }
FImage: TW3Image;
FGraph: TW3GraphicContext;
FButton: TW3Button;
procedure HandleButtonClicked(Sender:TObject);
protected
{ Protected methods }
Procedure InitializeObject;override;
Procedure FinalizeObject;override;
Procedure StyleTagObject;override;
procedure resize;Override;
end;

Implementation

//############################################################################
// TForm1
//############################################################################

Procedure TForm1.InitializeObject;
Begin
inherited;
FImage:=TW3Image.Create(self);
FImage.Background.fromColor(clWhite);
FButton:=TW3Button.Create(self);
FButton.OnClick:=HandleButtonClicked;
FButton.Caption:=’Click to generate’;
FGraph:=TW3GraphicContext.Create(NIL);
End;

Procedure TForm1.FinalizeObject;
Begin
FImage.free;
FButton.free;
FGraph.free;
inherited;
End;

procedure TForm1.HandleButtonClicked(Sender:TObject);
var
FCanvas: TW3Canvas;
aFrom: String;
aTo: String;
Begin
FGraph.Allocate(FImage.Width,FImage.Height);
FCanvas:=TW3Canvas.Create(FGraph);
try

// Clear background
FCanvas.fillstyle:=’rgb(0,0,99)’;
FCanvas.fillrectF(0,0,FGraph.Width,FGraph.Height);

// Draw some text on the canvas
FCanvas.font:=’10pt verdana’;
FCanvas.FillStyle:=’rgb(255,255,255)’;
FCanvas.FillTextF(‘This was generated on a canvas!’,10,20,MAXINT);

//You can load it in as a picture
FImage.LoadFromUrl(FCanvas.toDataUrl(”));

//.. or load it as a background to a picture (or control)
//FImage.background.fromUrl(FCanvas.toDataUrl(”));

finally
FCanvas.free
end;
FGraph.release;
end;

procedure TForm1.resize;
var
hd: Integer;
dy: Integer;
Begin
FImage.setBounds(5,5,width-10,(height div 2) + (height div 3) );
hd:=height – (FImage.top + FImage.Height + 5);
dy:=(hd div 2) – (FButton.height div 2);
FButton.setBounds(5,dy + FImage.Top + FImage.height,width-10,FButton.height);
end;

Procedure TForm1.StyleTagObject;
Begin
inherited;
StyleClass:=’TW3CustomForm’;
End;

end.

[/sourcecode]

Articles about Smart

Posted on 07.01.2012 by Jon Lennart Posted in News
Not your father's "hello world"

Not your father's "hello world"

The well known programming guru and author of Omni Thread Library, Primoz Gabrijelcic, have given the alpha version of Smart Mobile Studio a run for it’s money. He has produced two articles (in a planned series of articles) about how to implement a fully operational fractal explorer under Smart.

We consider it an honour to have Primoz giving our system a solid test-drive. Primoz Gabrijelcic is well known in the Delphi community for both his skill and insight into all things technical.

The first article can be found here:

http://www.thedelphigeek.com/2012/01/first-steps-with-smart-mobile-studio.html

And the latest installment can be read here:

http://www.thedelphigeek.com/2012/01/my-first-smart-program.html

A simple sprite-sheet

Posted on 06.01.2012 by Jon Lennart Posted in Developers log

A sprite sheet is basically just an image. But it’s an image that is organized in a special way, usually with a 32×32 or 64×64 pixel grid where each cell contains either a character animation frame – or a background tile. Back in the old Amiga days of 8 bit graphics and hand crafted sprites this was the only way to go.

Since the world of mobile javascript game development is more or less en-par with the old Amiga (in terms of cpu power and restrictions. Which is amazing since the Amiga had a 1hz motorola mc68000 CPU) an example of a spritesheet class might come in handy.

Classical sprite sheet from sega

Classical sprite sheet from sega

A simple spritesheet class

TW3SpriteSheet = class(TObject)
private
  FImage:     TW3Image;
  FReady:     Boolean;
  FColumns:   Integer;
  FRows:      Integer;
  FTotal:     Integer;
  FWidth:     Integer;
  FHeight:    Integer;
  FOnReady:   TNotifyEvent;
  procedure   HandleImageReady(sender:TObject);
  procedure   SetWidth(aValue:Integer);
  procedure   Setheight(aValue:Integer);
  Procedure   ReCalcInfo;
public
  Property    OnReady:TNotifyEvent read FOnReady write FOnReady;
  Property    SpriteWidth:Integer read FWidth write setWidth;
  Property    SpriteHeight:Integer read FHeight write setHeight;
  Property    Ready:Boolean read FReady;
  Procedure   LoadImage(aUrl:String);
  Procedure   Draw(Canvas:TW3Canvas;dx,dy:Integer;FrameIndex:Integer);
  Constructor Create;virtual;
  destructor  Destroy;Override;
end;

constructor TW3SpriteSheet.Create;
begin
  inherited Create;

  FWidth  := 32;
  FHeight := 32;
  FColumns := 0;
  FRows  := 0;
  FTotal := 0;

  FImage := TW3Image.Create(NIL);
  FImage.OnLoad := HandleImageReady;
end;

destructor TW3SpriteSheet.Destroy;
begin
  FImage.onLoad:=NIL;
  FImage.free;
  inherited;
end;

procedure TW3SpriteSheet.setWidth(aValue:Integer);
begin
  FWidth:=w3_ensureRange(aValue,4,MAXINT);
  ReCalcInfo;
end;

procedure TW3SpriteSheet.setheight(aValue:Integer);
begin
  FHeight:=w3_ensureRange(aValue,4,MAXINT);
  ReCalcInfo;
end;

procedure TW3SpriteSheet.ReCalcInfo;
begin
  if FReady then
  begin
    FColumns:=FImage.Width div FWidth;
    FRows:=FImage.Height div FHeight;
    FTotal:=FColumns * FRows;
  end else
  begin
    FColumns:=0;
    FRows:=0;
    FTotal:=0;
  end;
end;

procedure TW3SpriteSheet.HandleImageReady(sender:TObject);
begin
  FReady:=True;
  ReCalcInfo;

  if assigned(FOnReady) then
    FOnReady(self);
end;

procedure TW3SpriteSheet.LoadImage(aUrl:String);
begin
  FReady:=False;
  ReCalcInfo;
  FImage.LoadFromUrl(aUrl);
end;

procedure TW3SpriteSheet.Draw(Canvas:TW3Canvas; dx,dy:Integer; FrameIndex:Integer);
var
  sx,sy:  Integer;
begin
  if  FReady
  and assigned(canvas)
  and (FrameIndex>=0)
  and (FrameIndex<FTotal) then
  Begin
    sx:=FrameIndex mod FColumns;
    sy:=FrameIndex div FRows;
    sx:=sx * FWidth;
    sy:=sy * FHeight;
    canvas.DrawImageEx2F(FImage.tagRef,sx,sy,FWidth,
    FHeight,dx,dy,FWidth,FHeight);
  end;
end;

Using the class

Using the class is simple. Initialize it in TApplication.ApplicationStarting method and load in a picture, like this:

  FSheet := TW3SpriteSheet.Create;
  FSheet.LoadImage('res/sprites.png');

When the actual sprite-sheet image is loaded, the “ready” property will be set to true. So in your PaintView method always check the ready flag before accessing it:

  if FSheet.Ready then
  begin
    FSheet.Draw(Canvas,100,100,10); // draw tile #10
    FSheet.Draw(Canvas,133,100,11); // draw tile #11
    FSheet.Draw(Canvas,166,100,12); // draw tile #12
  end;

Enjoy!

How do i plot pixels on a offscreen bitmap?

Posted on 06.01.2012 by Jon Lennart Posted in Documentation

Just like ordinary Delphi, Javascript has it’s own canvas object. As you can imagine the canvas of the browser is quite different from the good old Delphi TCanvas, but not so alien that it doesn’t have it’s similarities. But you will need to brush up on the documentation from Apple in order to use it.

But HTML5 also have something else up it’s sleeve, namely that you can create off-screen bitmaps (wrapped in the TW3ImageData class from w3graphics.pas). The difference between a Delphi bitmap and a HTML5 bitmap is 3 fold:

  • The bitmap is obtained from the canvas, not the other way around (Delphi’s TBimap has a canvas property)
  • Off-screen bitmaps do not have a canvas, they are in reality DIBS (device independent bitmaps)
  • Off-screen bitmaps are 32bit exclusively (RGBA, 8888 format).

This is actually good news because it means we can create games and multimedia dealing with pixel data rather than the (excuse me) somewhat cumbersome canvas object. Most javascript developers actually avoid this part because they are used to “high level” coding only – but coders coming from the Delphi community have been knocking out low level graphics libraries for ages. So if you have ever played around with DIBS (device independent bitmaps) in Delphi – you should feel right at home.

Here is a quick example of how to plot some pixels off-screen, and copy the results onto the screen (note: this is a game project):

[sourcecode language=”delphi”]
unit Project8;

interface

uses w3system, w3components, w3application,
w3game, w3gameapp, w3graphics, w3components;

type

TApplication=class(TW3CustomGameApplication)
private
{ Private methods }
FBuffer: TW3ImageData;
protected
{ protected methods }
procedure ApplicationStarting;override;
procedure ApplicationClosing;override;
Procedure PaintView(Canvas:TW3Canvas);override;
end;

Implementation

//############################################################################
// TApplication
//############################################################################

procedure TApplication.ApplicationStarting;
Begin
inherited;

//Initialize refresh interval, set this to 1 for optimal speed
GameView.Delay:=20;

(* Create a our "offscreen bitmap" *)
FBuffer:=GameView.Canvas.CreateImageData(32,32);

//Start the redraw-cycle with framecounter active
//Note: the framecounter impacts rendering speed. Disable
//the framerate for maximum speed (false)
GameView.StartSession(true);
End;

procedure TApplication.ApplicationClosing;
Begin
GameView.EndSession;

inherited;
End;

// Note: In a real live game you would try to cache as much
// info as you can. Typical tricks are:
// 1: Only get the width/height when resized
// 2: Pre-calculate strings, especially RGB/RGBA values
// 3: Only redraw what has changed, avoid a full repaint
// The code below is just to get you started

procedure TApplication.PaintView(Canvas:TW3Canvas);
Begin
// Clear background
canvas.fillstyle:=’rgb(0,0,99)’;
canvas.fillrectF(0,0,gameview.width,gameview.height);

// Draw our framerate on the screen
canvas.font:=’10pt verdana’;
canvas.FillStyle:=’rgb(255,255,255)’;
canvas.FillTextF(‘FPS:’ + IntToStr(GameView.FrameRate),10,20,MAXINT);

// plot some pixels
if FBuffer<>NIL then
Begin
FBuffer.setPixelC(0,2,clGreen);
FBuffer.setPixelC(1,2,clGreen);
FBuffer.setPixelC(2,2,clGreen);

FBuffer.setPixelC(0,4,clRed);
FBuffer.setPixelC(1,4,clRed);
FBuffer.setPixelC(2,4,clRed);

// paste graphics to display
Canvas.putImageData(FBuffer,20,20);
end;
End;

end.

[/sourcecode]

The result may not look so impressive right now, but it’s the foundation for what will become a very impressive browser based graphics system:

Pixels galore

Pixels galore

In the future we are going to add a lot more functionality to the TW3ImageData class. Things like line, ellipse, fillrect, circle and flood-fill is already prototyped. But if you feel like playing around with pixels – this is a good start.

Open the file w3graphics.pas and have a look at the methods and properties of TW3ImageData for more information. Also check out this excellent canvas tutorial by Mark Pilgrim.

How do I rotate a control by X degrees?

Posted on 05.01.2012 by Jon Lennart Posted in Documentation

All descendants of TW3Customcontrol, which is the primary object most visual controls derive from, has a property called Angle. This is a floating point property which will rotate your control in whatever angle you define. Please bear in mind that this property will override any webkit rotation in the current style. If you want the stylesheet to retain it’s position, mark the CSS tag with !important;

For instance:

[sourcecode language=”delphi”]
unit Form1;

interface

uses w3system, w3ctrls, w3forms, w3application;

type
TForm1=class(TW3form)
private
{ Private methods }
FButton: TW3Button;
Procedure HandleClick(Sender:TObject);
protected
{ Protected methods }
Procedure InitializeObject;override;
Procedure FinalizeObject;override;
Procedure StyleTagObject;override;
end;

Implementation

//############################################################################
// TForm1
//############################################################################

Procedure TForm1.InitializeObject;
Begin
inherited;
FButton:=TW3Button.Create(self);
FButton.caption:=’Click me’;
FButton.setBounds(100,50,100,28);
FButton.onClick:=HandleClick;
End;

Procedure TForm1.HandleClick(Sender:TObject);
Begin
if FButton.Angle=60 then
FButton.Angle:=0 else
FButton.Angle:=60;
end;

Procedure TForm1.FinalizeObject;
Begin
inherited;
End;

Procedure TForm1.StyleTagObject;
Begin
inherited;
StyleClass:=’TW3CustomForm’;
End;

end.

[/sourcecode]

When you click the button it will toggle between normal (0 deg) and tilted (60 deg), like this:

Best not to over do it

Best not to over do it

How do i create and use a timer?

Posted on 05.01.2012 by Jon Lennart Posted in Documentation

Under Delphi and free-pascal there is a component called TTimer. Under Smart Mobile Studio however all types of timer objects have a slightly different architecture – and also different names (we will probably provide a TTimer alias before release). The class you are looking for is called “TW3EventRepeater”.

To use a timer start by adding the unit “w3time” to your unit’s uses section. Unlike Delphi, TW3EventRepeater derives from TObject rather than TComponent. There is no point in creating a component (which adds quite a bit of overhead) when a normal object will do.

Using the event repeater from a form is a snap:

[sourcecode language=”delphi”]
unit Form1;

interface

uses w3system, w3ctrls, w3forms, w3application, w3time;

type
TForm1=class(TW3form)
private
{ Private methods }
FTimer: TW3EventRepeater;
FCount: Integer;
function HandleTimer(sender:TObject):Boolean;
protected
{ Protected methods }
Procedure FormActivated;override;
end;

Implementation

//############################################################################
// TForm1
//############################################################################

Procedure TForm1.FormActivated;
Begin
FTimer:=TW3EventRepeater.Create(HandleTimer,1000);
end;

function TForm1.HandleTimer(sender:TObject):Boolean;
Begin
result:=False;
inc(FCount);
if FCount>9 then
Begin
TW3EventRepeater(sender).free;
result:=true;
w3_showmessage(‘time is up!’);
end;
end;

end.
[/sourcecode]

As expected the timer kicks in after 10 seconds informing us that the time has expired

The timer works just like we expect

The timer works just like we expect

You may have noticed that the callback was a function and not a procedure? If you return “true” the timer will stop of it’s own accord. Since this is javascript and not winapi you can actually dispose of the timer while the timer is called. Because the timer object does not go out of scope until the function returns.

Pages

  • About
  • Feature Matrix
  • Forums
  • News
  • Release History
  • Download
  • Showcases
    • The Smart Contest 2013, Round 1 – Graphics
  • Store
  • Documentation
    • Creating your own controls
    • Debugging, exceptions and error handling
    • Differences between Delphi and Smart
    • Get the book
    • Getting started
      • Introduction
      • Local storage, session storage and global storage
      • Application architecture
      • The application object
      • Forms and navigation
      • Message dialogs
      • pmSmart Box Model
      • Themes and styles
    • Layout manager
    • Networking
      • Loading files
      • TW3HttpRequest
      • TW3JSONP
    • Prerequisites
    • Real data, talking to sqLite
    • System requirements
    • Project types
      • Visual project
      • Game project
      • Console project

Archives

  • December 2019
  • December 2018
  • November 2018
  • July 2018
  • June 2018
  • February 2018
  • September 2017
  • April 2017
  • November 2016
  • October 2016
  • September 2016
  • April 2016
  • March 2016
  • January 2016
  • October 2015
  • September 2015
  • July 2015
  • April 2015
  • January 2015
  • December 2014
  • October 2014
  • September 2014
  • August 2014
  • July 2014
  • June 2014
  • March 2014
  • February 2014
  • January 2014
  • December 2013
  • November 2013
  • October 2013
  • August 2013
  • July 2013
  • June 2013
  • May 2013
  • April 2013
  • March 2013
  • February 2013
  • January 2013
  • December 2012
  • November 2012
  • August 2012
  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • November 2011
  • October 2011
  • September 2011

Categories

  • Announcements (25)
  • Developers log (119)
  • Documentation (26)
  • News (104)
  • News and articles (16)

WordPress

  • Register
  • Log in
  • WordPress

Subscribe

  • Entries (RSS)
  • Comments (RSS)
  • Prev
  • 1
  • …
  • 3
  • 4
  • 5
  • 6
  • 7
  • Next
© Optimale Systemer AS