Author Topic: [C/ Win32 GDI] How to make a bitmap 'wobble'?  (Read 422 times)

0 Members and 1 Guest are viewing this topic.

Offline SilentWorld

  • ZX 81
  • *
  • Posts: 5
  • Karma: 0
    • View Profile
[C/ Win32 GDI] How to make a bitmap 'wobble'?
« on: September 29, 2020 »
The wobble effect is one of my all-time favourites. It is simple but always nice and hypnotic to look at. I am using C and plain GDI for my projects and want to learn how to apply this effect to a bitmap. From my basic understanding, each column or row of pixels moves using sine modulation. I've heard that this probably isn't the best way to do it, but I'm admittedly terrible at math. My programming ability is that of a beginner, however I've been hacking around with the GDI and managed to learn a thing or two. Any help is appreciated!

Offline Optimus

  • DBF Aficionado
  • ******
  • Posts: 2453
  • Karma: 128
    • View Profile
    • Optimouse Demo Site
Re: [C/ Win32 GDI] How to make a bitmap 'wobble'?
« Reply #1 on: October 02, 2020 »
There are many ways to do wobble. There is wobble only on X and wobble both on X and Y. The later is the yummie one :)

Sines would do it but used as look up tables (depending on the system your are working, in my opinion in modern GPUs with shaders, just go pure math,. but in software rendering even in modern PCs integer LUTs for sines would still be faster).

It's going to be a regular loop over X,Y bitmap pixels. Pseudocode
for (int y=0; y<height; ++y) {
  int offsetY = sin(x * freq) * offsetHeight;
  for (int x=0; x<width; ++x) {
    int offsetX = sin(y * freq) * offsetWidth;
    putpixel(x,y, bitmap[x + offsetX][y + offsetY]);
  }
}

Of course don't use putpixel or sin directly,. that's just pseudo code. You can do more complex sines on the offsets, like offset = sin(x * freq1) + sin(x * freq2)

The other way, if you don't want to do per pixel offset is to split the screen into a grid of quad polygons, e.g. every 16*16 pixels, then offset the vertices (or the texture coordinates alternativelly). Interpolate texture between grid points. This way you could use float maths only for few point and not per pixel and still be fast enough, if you don't want to use LUTs. But I think the first per pixel method with some precalc of the sines in LUTs could be much easier, unless you are on a system with a texture rendering engine already.
Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1422
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Re: [C/ Win32 GDI] How to make a bitmap 'wobble'?
« Reply #2 on: October 10, 2020 »
Thanks for explaining Optimus!
Here is a small test done in purebasic, which is probaly not the same effect as you guys are talking about and the result is a bit wired. (Image is mirrored a special point)
Move mouse hoizontal to change frequence... move mouse vertical to change offsetHeight.

Code: [Select]
; Small bitmap effect example - va!n in 10/2020

InitSprite()
InitKeyboard()
InitMouse()
OpenScreen(640,480,32,"")

LoadSprite(1,"d:\Unbenannt.bmp",0)

sprH = SpriteHeight(1)

Repeat
  ExamineKeyboard()
  ExamineMouse()
 
 
  ClearScreen(0)
   
;   For (int y=0; y<height; ++y) {
;   int offsetY = Sin(x * freq) * offsetHeight;
;   For (int x=0; x<width; ++x) {
;     int offsetX = Sin(y * freq) * offsetWidth;
;     putpixel(x,y, bitmap[x + offsetX][y + offsetY]);
;   }
; }
 
 
  offsetHeight = MouseY()   
  freq.f =   MouseX() / 10000  ; 0.004;MouseX() / 1000
 
  For y = 0 To sprH
    offsetY = Sin(y * freq) * offsetHeight
    ClipSprite(1,0,offsetY,SpriteWidth(1),1)
    DisplaySprite(1, 0, y)
  Next
 
  FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)

End
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline SilentWorld

  • ZX 81
  • *
  • Posts: 5
  • Karma: 0
    • View Profile
Re: [C/ Win32 GDI] How to make a bitmap 'wobble'?
« Reply #3 on: October 24, 2020 »
Hi guys. Thanks for your suggestions! I have been working on some variations of the effect using some FreeBasic source and a with a little help. The math is a clearer to me now too :)  Here is the code loosely modified from the original written by Dr_Davenstein. I might be wrong, but the win32 equivalents of PSET, PUT and GET would be SrcCopy, BitBlt, and SelectObject. Sorry for the late reply, I was getting a 403 error for a long time which prevented me.

Code: [Select]
#Include "fbgfx.bi"
Screenres 340,120,32,,

Dim As Integer x, y
Dim As Ubyte Ptr buf  = imagecreate(239,44)
Dim As Ubyte Ptr buf2  = imagecreate(239,44)
Bload "blogo.bmp", buf
Color &HFFFFFF, &HFF00FF
Dim As double Ang
Dim As double Ang_x
Dim As double Amplitude
Dim As Integer period
Dim As double frequency
Dim As double delta

Amplitude = 5.0
period = 60
frequency = 1.0
delta = 0.01

Do
    screensync
    ScreenLock
    cls
   
    Ang+= 6.282 * frequency * delta
    Ang_x = Ang
   
    For x = 0 To 238
        Ang_x+=(6.282/period)
        Get buf, (x,0)-(x,43), buf2
         
        Put(x+10,(Amplitude*sin(Ang_x))+30), Buf2, pset
    Next                           
   
    ScreenUnlock
    sleep delta * 1000
   
Loop Until Multikey(FB.SC_ESCAPE)

imageDestroy(buf)
imageDestroy(buf2)

Offline va!n

  • Pentium
  • *****
  • Posts: 1422
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Re: [C/ Win32 GDI] How to make a bitmap 'wobble'?
« Reply #4 on: October 25, 2020 »
Could you add an compiled version (exe) please? ;)
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline SilentWorld

  • ZX 81
  • *
  • Posts: 5
  • Karma: 0
    • View Profile
Re: [C/ Win32 GDI] How to make a bitmap 'wobble'?
« Reply #5 on: October 25, 2020 »
Could you add an compiled version (exe) please? ;)

Sure! I've attached all the executables for each variation, along with their source code. Again this would not have been possible without help, but  I have learned a few things. Of course, the real challenge will be to make this work in pure GDI. Feel free to suggest improvements to this code :)

Offline va!n

  • Pentium
  • *****
  • Posts: 1422
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Re: [C/ Win32 GDI] How to make a bitmap 'wobble'?
« Reply #6 on: October 26, 2020 »
thanks for the archive with all versions and sources.

i think you should try to DIB (Win32 GDI API) as screenbuffer. You could read/write pixels very fast, by just peek/poke values.
Btw, i think you can optimize your effects a lot without the need to manipulate each pixel. For example:

For your horizontal effect, just store the image into a DIB secion and copy the full image row to the required x position of the DIB screenbuffer.
CopyMemory() may be your friend. So you just only copy one full row in once, instead copy pixel by pixel.

For the Verticval effect you could do the same for best performance and when done, just rotate the image 90 degree.

For not effects you could use the same techniuqe. First change hoizontal offeset of each y row. rotate it internaly 90 degree. Your y value is now x and change again the x offset. rotate 90 degree and you are done.

in short:  i think you can improve performance a lot, by copying full parts (rows) of your image.

- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline SilentWorld

  • ZX 81
  • *
  • Posts: 5
  • Karma: 0
    • View Profile
Re: [C/ Win32 GDI] How to make a bitmap 'wobble'?
« Reply #7 on: November 01, 2020 »
No problem :)

I haven't used DIB at all before so I will need to reference either Petzold or Feng Yuan's book. Correct me if I'm wrong, but the main advantage of using them is that one has direct access to pixels in a DC? In the Freebasic code, this appears to be taken care of. My initial idea, was to load a normal bitmap and make it into a "tilesheet" in memory and iterate over each image in it. This would no doubt be too slow, even if the effect is only going to be used once.