Recent

Author Topic: Mapping Images Like Odometer  (Read 590 times)

SandyG

  • Full Member
  • ***
  • Posts: 116
Mapping Images Like Odometer
« on: September 08, 2025, 02:13:25 am »
Was thinking of the next fun component to work on. I always like the basic Odometer from older cars as something fun. Seen a few in Javascript, but hard to translate to Pascal/BGRA so looking for some hints how to do something like this (Ignore the gear sprockets for now). The odometer is basically a slot machine wheel. The image that is spun has to be 'Bent' to the wheel diameter, and likely has some shading on the top or bottom (This is the easy part as can likely fake the eye out with simple shading).

1. Wheels could have arbitrary image, like a number, letter, or an image (Think of a slot machine)
2. Stack arbitrary number of 'wheels'
3. Partial images as the wheel rolls around and support arbitrary 'roll angle' so can possibly animate the wheel moving
4. Related Background, Spacing, etc.

I was playing with some of the BGRA's FillPolyPerspectiveMapping() function as a possible way to do with some lower fidelity in the wrapping ability to, again just trick the eye in seeing some depth to make it look like it's wrapping.

The idea would be to generate a Bitmap of all the characters and do a 'lens' over the area of interest to map / translate the area of the image to be bent like on a wheel.

Not sure if this is a simple geometric transformation (given a cylinder diameter create a function to scale the width of a scan line???).

Open for help and staring points, or if you know of a component that I can work on like this that's even better.

Thanks

Sandy

circular

  • Hero Member
  • *****
  • Posts: 4450
    • Personal webpage
Re: Mapping Images Like Odometer
« Reply #1 on: November 03, 2025, 11:30:16 am »
Hi Sandy,

Making an odometer seems like a fun idea  :)

I suppose there are various level of detail in the transformation :
  • not transform, just translate and the symbols are clipped. This is simplistic but actually often done.
  • do a lense effect so that the symbols are shrunk vertically at the top and bottom instead of being clipped.
  • do a full 3D effect so that the symbols are shrunk vertically but also slightly reduced horizontally.

Doing the vertical shrinking is not too difficult to do. It is indeed a cylinder transformation and you only need a formula to map the Y coordinate. For the full 3D effect, you need to map the X coordinate as well or use actual 3D drawing function like FillPolyPerspectiveMapping.

You can start by making a custom scanner to do the cylinder transform. It would be a bit similar to TBGRAVerticalCylinderDeformationScanner that you can find in BGRATransform unit, except that it changes the other coordinate. Also you probably want to have a source image that is bigger vertically by a factor of Pi/2, so that in the middle, the image is not stretched.

The scanner would be something like that (not tested and not optimized):

Code: Pascal  [Select][+][-]
  1. const
  2.   OdometerDeformationSourceRatio = 1.570796326794897; {PI/2}
  3. type
  4.   { Scanners that distorts as a horizontal cylinder shape with a ratio }
  5.   TBGRAOdometerDeformationScanner = Class(TBGRACustomScanner)
  6.   protected
  7.     FScanner: IBGRAScanner;
  8.     FScanAtFunc: TScanAtFunction;
  9.     FCenterY: single;
  10.     FRadiusY: single;
  11.     FSourceRatioY: single;
  12.   public
  13.     constructor Create(AScanner: IBGRAScanner; ATargetSizeY: single;
  14.       ASourceRatioY: single = OdometerDeformationSourceRatio);
  15.     function ScanAt(X, Y: Single): TBGRAPixel; override;
  16.   end;
  17.  
  18. constructor TBGRAOdometerDeformationScanner.Create(
  19.   AScanner: IBGRAScanner; ATargetSizeY: single; ASourceRatioY: single);
  20. begin
  21.   FScanner := AScanner;
  22.   FScanAtFunc := @FScanner.ScanAt;
  23.   FCenterY := ATargetSizeY/2 - 0.5;
  24.   FRadiusY := ATargetSizeY/2;
  25.   FSourceRatioY := ASourceRatioY;
  26. end;
  27.  
  28. function TBGRAOdometerDeformationScanner.ScanAt(X, Y: Single): TBGRAPixel;
  29. var
  30.   yn: Single;
  31. begin
  32.   // computes normalized position [-1..1] on target
  33.   yn := (y - FCenterY) / FRadiusY;
  34.   if (abs(yn) <= 1) then
  35.   begin
  36.     // apply curvature
  37.     yn := (2 / Pi) * arcsin(yn);
  38.     // retrieve pixel in source
  39.     result := FScanAtFunc(x, (yn * FRadiusY + FCenterY)*FSourceRatioY);
  40.   end
  41.   else
  42.     result := BGRAPixelTransparent; // outside of range
  43. end;
Conscience is the debugger of the mind

SandyG

  • Full Member
  • ***
  • Posts: 116
Re: Mapping Images Like Odometer
« Reply #2 on: November 14, 2025, 06:56:55 am »
OK, going to find some time to work on this. Had to take a break for a bit, but looking for more late night fun.

Have to start looking at the code and build a simple sample.

The odometer would be just one application, I keep thinking of a slot machine as well :)

Thanks for the help to get a jump start on this.

Sandy


SandyG

  • Full Member
  • ***
  • Posts: 116
Re: Mapping Images Like Odometer
« Reply #3 on: November 14, 2025, 11:53:01 pm »
Got it working to roll an image around.

Didn't realize how the scanners worked, but really this is just the Horizontal version of the mapping to a cylinder.

Have to play around with some parameters so you could easily adjust 'wheel' diameter, width, and faster mapping.

My strategy will be to make an array of what ever the images are for the wheel, ie, digits, or images. Then figure out how to draw them quickly as it would scroll showing top and bottoms of rolling images to simulate the wheel.

Not quite sure yet how to do it all, but the simple test program rolling a text in and out of the view looks really good.

Some more time to ponder :)

Sandy

« Last Edit: November 14, 2025, 11:55:44 pm by SandyG »

 

TinyPortal © 2005-2018