old-school scrolltext using bitmapped fonts. How?

I need a way to grab a squared area of a bitmap, to display it on screen. My bitmappedfont is 320x288 big containing images each 25x25 (these are not the actuale sizes :wink: ).

I need code/example on how to grab for example the 14th “character” from the bitmap, returning it as a ImageItem. How to do such? Can anyone remember the old-skool horizontal scrolltexts “demo”/intro’s on the ole’ 8-bit computers (Amiga, Commodore64, Atari)? Such a scroller is my intention.

This is a short snippet of my code.

      
               Sprite tmpSprite4 = new Sprite(objImages1.image.getImage(), 320, 288);
                LayerManager laagBeheer1 = new LayerManager();
                laagBeheer1.append(tmpSprite4);
                tmpSprite4.setPosition(5, 5);

                laagBeheer1.paint(this.graphics1, xpos, ypos);  //put the sprite in position

Actually my idea is to port some code of mine from BlitzMax to J2ME. This is the BlitzMax-verison of the scroller…

http://www.gdb1.nl/podcast/informatie_analyse_voor_n00bs/media/Informatie%20analyse%20voor%20n00bs_afl005/Amigacopper_demo01_klein.jpg

Off the top of my head.

For a 2 dimensional bitmap tile. If you only need one, you can figure that out for yourself.
But the code is the same more or less.

Disclaimer: no checks or anything. Please insert on your own.


int tileWidth = imageWidth / numberOfCols;
int tileHeight = imageHeight / numberOfRows;

public void drawFrame (int col, int row, int xPos, int yPos ) {
  int x = xPos;
  int y = yPos;

  // this could be done above but I prefer to show it this way as it makes the steps a little clearer.
  x -= col * tileWidth;
  y -= row * tileHeight;

  setclip( x, y, tileWidth, tileHeight);
  drawImage( image, x, y, Graphics.TOP|Graphics.LEFT);
}

remember to reset the clip afterwards or (better) before each rendering.

It is also possible to use translations but IIRC there are some devices that are buggy.
If you just want to get the demo running on a few devices, then it should be ok to use.

Some things to remember:
Never copy an image onto another image. You will lose your transparency.
If you are using MIDP2.0 or only Nokia devices you can also use the direct pixel rendering features that also support alpha values.

http://www.java-gaming.org/forums/index.php?action=post;topic=17434.0;num_replies=1

Great tip :). BUT, the java compiler dont know about setClip. My project is J2ME in netbeans 5.5. I am quite proficient at C# but really n00b with java.

Is my code missing a library?

Netbeans 5.5 generates this error (the line numbers above wont match here :wink: )

Compiling 12 source files to C:\michiele\Programmering\Java\J2ME\Sandput\scrolltext01\build\compiled
C:\michiele\Programmering\Java\J2ME\Sandput\scrolltext01\src\AmigaScrollerEenvoudig01\clsTiledImage.java:37: cannot find symbol
symbol  : method setclip(int,int,int,int)
location: class AmigaScrollerEenvoudig01.clsTiledImage
        setclip( x, y, tileWidth, tileHeight);

here is example code;


/*
 * clsLettertjes.java
 *
 * Created on 30 augustus 2007, 12:14
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package AmigaScrollerEenvoudig01;

import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;
import pappavis.routeplanner.*;

/**
 *
 * @author pappavis
 */
public class clsLettertjes  {
        String CLASS_NAME = "clsLettertjes";

	public Vector AllAppObjects;
	public String ScrollText;
	public int newXPos1;			//'dit houd die startpositie van de tekst op de éérste frame.
	public int newYPos1;			//'dit houd die startpositie van de tekst op de éérste frame.

    int tileWidth, tileHeight;

    /** Creates a new instance of clsLettertjes */
    public clsLettertjes() {
    }
	
     // http://www.java-gaming.org/forums/index.php?topic=17434.0
    public void drawFrame (int col, int row, int xPos, int yPos )
    {
        int x = xPos;
        int y = yPos;

        // this could be done above but I prefer to show it this way as it makes the steps a little clearer.
        x -= col * tileWidth;
        y -= row * tileHeight;

        setclip( x, y, tileWidth, tileHeight);
        drawImage( image, x, y, Graphics.TOP|Graphics.LEFT);
    }     
}

My font bitmap:

http://eikenlaan.org/merasmus/podcast/informatie_Analyse_voor_n00bs/media/circlefont.png

Credits: flameduck @blitzbasic.com

.

[quote=“pappavis,post:3,topic:30661”]
You need a Graphics object to set the clipping for! (get it from the paint() method of your midlet).
Take a look at some of the examples that come with the (free) sun WTK: http://java.sun.com/products/sjwtoolkit/

@pappavis:
Well it was pseudo code that you were supposed to make work on your own. :wink:

Like SimonH says, you need the graphics object which is passed from the Canvas’ paint method.

If you are missing a library? Well if you have not added any libs, then probably.
I would suggest you get the WTK emulator and just include the libs from there as IIRC it has all the libs that are really needed.

If you are aiming for lowest common denominator, only include the MIDP1.0 lib.

One more thing. Working on J2ME can be a challenge. Low memory, weak CPUs, slow displays. And when you are working on games or graphical applications such as a demo it is all the more important.
So optimise your heart out!

If you have any questions, post them and we will try and help.
You can also post/send the code if you like.

This is my first attempt at doing anything with Java. This bedroom-rpogrammer idea is to recreate the ol’ 8-/16-bit scrolltext found on AMiGA, Commodre64 etc. but then do it on J2ME.

My code need to more or less do the following;

  1. Read a text string into an array.
  2. Associate each letter (element) in the array with an appropriate letter.
  3. Draw all letters after each other on displayarea (the screen) from left to right.
  4. Shift all X-positions of the letters a few pixels to left.
  5. Repeat (3) until the last letter has disappeared to the left side of the screen.

The aforementioned is no problem coz such is running in a window$ BlitzMax .exe already. See earlier post for a screenshot. My problem is step (2) and (3) in the above process. Blitzmax have a neat feature that it handles tiledbitmaps nifty:

BlitzMax-code;


Function paint()
  DrawImage(imgTiledImage, Xpos, Ypos, frames, tileWidth, tileHeight, tileNumber); '//this way just 
Endfunction

Some info’s;
The tiled bitmap (see earlier post) containing my font is 320 x 288 Pixels.
The letters are each 32x32 big.

To draw ‘#’ the third letter from the top in the bitmap must be taken.
I just cant get getclip() to work the way it apparentley could. There is drawn sumthing wrong or nothing.

this is a sample of my javacode, which should emulate the BlitzMax functionality;

        
   /** paint the current animation frame */
     private void Paint(clsLettertje objLettertje)  throws Exception
    {
        String METHOD_NAME = "Paint";
        
        if(objLettertje == null)
        {  
            return;
        }
        
        if(this.graphics1 != null)
        {
            try {
                clsLetterInMatrix displayObjInfo2 = this.GetLetterPosInTiledImage(objLettertje.TekstWaarde);
                
                if(displayObjInfo2 != null)
                {
                    clsTiledImage tiledimg1 = new clsTiledImage(this.graphics1);
                    tiledimg1.setImage(objLettertje.image.getImage());
                    tiledimg1.tileHeight = 32;
                    tiledimg1.tileWidth = 32;
                    tiledimg1.drawFrame(displayObjInfo2.Kolom, displayObjInfo2.Rij, 40, 20);
                }
            } catch (Exception objErr1) {
                String strMelding2 = objErr1.getMessage();
                throw new Exception("  Fout in " + CLASS_NAME + "." + METHOD_NAME + " --> " + strMelding2);
            }
            //'this.graphics1.drawImage(objLettertje.image.getImage(), objLettertje.CurrPosX1, objLettertje.CurrPosY1, 0);
        }
    }

The method drawFrame uses the code frm earlier post. If the program code could produce a scrolltext on the emulator it should probably be run on my Samsung E900 as well . My dev environment is Netbeans 5.5 with J2ME kit installed.

This should be sumthing trivial.

This code is the bare minimum for a working MIDlet which shows clipping in action. If you can get this compiled and running you should be OK from there! (tip: try it in the WTK as well as Netbeans)

The MIDlet;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

public class MyMIDlet extends MIDlet implements CommandListener {

    Display display;
    MyCanvas canvas;		// The main screen

/***************************************************************************
 **************************************************************************/
    public MyMIDlet() {
        display = Display.getDisplay(this);
        canvas = new MyCanvas(display);
    }
/***************************************************************************
 **************************************************************************/
    public void startApp() throws MIDletStateChangeException {
        canvas.start();
    }
/***************************************************************************
 **************************************************************************/
    public void pauseApp() {}
/***************************************************************************
 **************************************************************************/
    public void destroyApp(boolean unconditional)
        throws MIDletStateChangeException {
                canvas.destroy();
    }
/***************************************************************************
 **************************************************************************/
    public void commandAction(Command c, Displayable s) {
        // code for command keys goes here
    }
/***************************************************************************
 **************************************************************************/
}

and the Canvas;

import javax.microedition.lcdui.*;
import javax.microedition.io.*;

public class MyCanvas extends Canvas implements Runnable {

    Display display;

/***************************************************************************
 **************************************************************************/
    public MyCanvas(Display displayIn) {
        display = displayIn;
    }
/***************************************************************************
 **************************************************************************/
    public void keyPressed(int keyCode) {}
    public void keyReleased(int keyCode) {}
/***************************************************************************
 **************************************************************************/
    void destroy() {}
/***************************************************************************
 **************************************************************************/
    void start() {
        display.setCurrent(this);
        Thread t = new Thread(this);
        t.start();
    }
/***************************************************************************
 **************************************************************************/
    public void run() {
        while (true)
        {
            repaint();
            serviceRepaints();
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {}
        }
    }
/***************************************************************************
 **************************************************************************/
    protected void paint(Graphics g) {
        // do your drawing here using g
        g.fillRect(0,0,100,50);
        g.setColor(0xffffff);
        g.drawString(new String("hello world"), 10, 10, 0);
        g.setClip(25,0,75,50);
        g.drawString(new String("clipped string"), 10, 20, 0);
    }
/***************************************************************************
 **************************************************************************/
}

@pappavis:
Call me slow but why are you using such complicated processes for such a task?

From what I can read (my dutch? is non-existent) you are calling the paint method for each letter?
In the paint method you are creating some object and then assigning the values and whatnot…

What you should do is reduce the rendering to it’s bare minimum.
Create your tiled sprite on app start and then only use it’s paint method when you want to draw the letters.

So how I might do it:
Use Simons Midlet and Canvas classes

  • add a Sprite class that handles the rendering of the tiles.
    this class should get the loaded image and the col- and row count and from that init all data
    the paint method should get the graphics context, position info and the col/row or an index you then generate col/row from.
    (then you have a good general purpose sprite class you can reuse)

    the paint method could look similar to the example I had pasted.

then when your midlet is running and paint is called you do

  • loop through the letters and get their image indexes
  • call the sprite class’ paint method and pass it the graphics context, position and index/cell/row information.

Good idea to also reset the clip to the screen size after you call mehods that might change the clip, seeing as there is no reset-clip-method.

@SimonH thanx for the example of SetClip.
@Overkill, thanx your idea for sprite works great.

The text scrolls :). Using a Spirte class and giving the tilewidth, heigh 32x32 the correct tile (“letter”) is indeed take from the tiledmap. However now a problem happens, that the letters are painted on screen causing ‘smudging’. Is setClip meant to fix that smudging?

here is my new Paint() method.

    /** paint the current animation frame */
     private void Paint(clsLettertje objLettertje)  throws Exception
    {
        String METHOD_NAME = "Paint";
        
        if(objLettertje == null)
        {  
            return;
        }
        
        if(this.graphics1 != null)
        {            
            try {
                clsLetterInMatrix displayObjInfo2 = this.GetLetterPosInTiledImage(objLettertje.TekstWaarde);
                
                if(displayObjInfo2 != null)
                {
                    this.graphics1.copyArea(0, 0, this.MidledWidth, this.MidledHeight, 0, 1, graphics1.TOP | graphics1.LEFT);
                    this.graphics1.setColor( 255, 255, 255 );
                    this.graphics1.drawRect(0, 0, this.MidledWidth, this.MidledHeight);
                    // plak die lettertje op scherm.
                    Image imgTilemap1 = objLettertje.image.getImage();
                    Sprite sprite1 = new Sprite(imgTilemap1, 32, 32);
                    sprite1.setFrame(displayObjInfo2.frameNumber);
                    sprite1.setPosition(objLettertje.CurrPosX1, objLettertje.CurrPosY1);
                    sprite1.paint(this.graphics1);[/i]                }
            } catch (Exception objErr1) {
                String strMelding2 = objErr1.getMessage();
                throw new Exception("  Fout in " + CLASS_NAME + "." + METHOD_NAME + " --> " + strMelding2);
            }
            //'this.graphics1.drawImage(objLettertje.image.getImage(), objLettertje.CurrPosX1, objLettertje.CurrPosY1, 0);
        }
    }

here is a screenshot about what happens;

http://swartskaap.googlepages.com/smeerkaas1.jpg

GREAT got it working 8) . Though its scrolling badly slowly. I am employing double buffering. The code is chunky, ineffecient etc. For now its a great achievement to me :D.

Download Netbeans 5.5 project here --> http://swartskaap.googlepages.com/j2me_scrolltext01.rar

this is double buffer helper class;


/*
 * clsBackBuffer.java
 *
 * Created on 6 oktober 2007, 11:18
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package AmigaScrollerEenvoudig01;
import javax.microedition.lcdui.*;
import javax.microedition.lcdui.game.*;

/**
 *
 * @author Michiel Erasmus
 */
public class clsBackBuffer {
    private String CLASS_NAME = "clsBackBuffer";
    private Graphics graphics1;
    private Image backBuffer;
    public int backBufferHeight;
    public int backBufferWidth;
    
    /** Creates a new instance of clsBackBuffer */
    public clsBackBuffer(int bufferWidth, int bufferHeight) {
        this.graphics1 = null;
        this.backBuffer = Image.createImage(bufferWidth, bufferHeight);
        this.graphics1  = backBuffer.getGraphics();
    }
   
    /** Build up the back double buffer */
    public void addSprite(Sprite sprite1) throws Exception
    {
        String METHOD_NAME = "drawFrame";
        
        try
        {
            sprite1.paint(this.graphics1);
        } catch (Exception objErr1) {
            String strMelding2 = objErr1.getMessage();
            throw new Exception("  Fout in " + CLASS_NAME + "." + METHOD_NAME + " --> " + strMelding2);
        }
    }
    
    public Image getBackbuffer() throws Exception
    {
        return this.backBuffer;
    }
}


Glad I can help.

You really do not need double buffering. You can keep it anyway.

No the set clip has nothing to do with the smudging.
Set clip sets a ‘window’ into which can be painted. Even if the image is larger, only that region is painted.

You probably do not clear the graphics before painting.

Why are you recreating the sprite in the paint loop?
Do that outside where you initialize the app.

Remove the try/catch and your exception throwing. Make your code safe yourself.

I presume this.graphics1 is your double-buffer?

I will download the source and take a look at it later.

Wow, I’ve never seen that hideous CLASS_NAME and METHOD_NAME style before. :o What’s wrong with using getClass().getName() and using the stack trace that the exception gives you? Both provide more information and since they’re automatically generated they don’t need to be maintained (and hence aren’t likely to drift out of sync).

Oh come on, relax a little bit.
Heck stack trances will work on a PC but not on a Mobile, but no one is blasting anyone for that slip up.

Best practice would be to make sure your code works safely without the need for try/catches or throwing around exceptions.
Besides try/catches would make an already weak mobile app even slower, it does not really help once the app is on the device.
You also do not have anywhere to write the information anyway as there is no console and most do not have any debugging support (and those that do have the least problems)

Worst of all, the emulator is no criteria if the app will run bug-free on the mobile or not.

Stack traces don’t work on J2ME? That’s unexpectedly rubbish. :frowning:

They do work, but of course on a mobile there’s no console! Some of the better devices (Sonys mostly) allow a console on a PC via Bluetooth/IR and most emulators support a console, so it’s not all that bad!

@pappavis - your code looks too complex to me - keep it simple is the 1st rule of j2me! There’s a good forum too: http://www.j2meforums.com/forum/ loads of handy tips in there.