Image noise: Difference between revisions

From Rosetta Code
Content added Content deleted
Line 708: Line 708:
===Optimized example===
===Optimized example===
A second example that is somewhat more optimized but maybe more complicated.
A second example that is somewhat more optimized but maybe more complicated.
(~2800fps on a Thinkpad x220 laptop)
(~2900fps on a Thinkpad x220 laptop)
<lang go>package main
<lang go>package main


Line 780: Line 780:
}
}


// Start one Go Thread per physical core
// Start one Go Thread per physical core + 1
last = time.Now()
last = time.Now()
for i := 1; i < tc; i++ {
for i := 0; i < tc; i++ {
go createNoise(win, screen)
go createNoise(win, screen)
}
}

Revision as of 10:59, 7 April 2012

Task
Image noise
You are encouraged to solve this task according to the task description, using any language you may know.

Generate a random black and white 320x240 image continuously, showing FPS (frames per second).

Sample image:

Ada

Library: Lumen

noise.ads: <lang Ada>with Lumen.Image;

package Noise is

  function Create_Image (Width, Height : Natural) return Lumen.Image.Descriptor;

end Noise;</lang>

noise.adb: <lang Ada>with Ada.Numerics.Discrete_Random;

package body Noise is

  type Color is (Black, White);
  package Color_Random is new Ada.Numerics.Discrete_Random (Color);
  Color_Gen : Color_Random.Generator;
  function Create_Image (Width, Height : Natural) return Lumen.Image.Descriptor is
     Result : Lumen.Image.Descriptor;
  begin
     Color_Random.Reset (Color_Gen);
     Result.Width := Width;
     Result.Height := Height;
     Result.Complete := True;
     Result.Values := new Lumen.Image.Pixel_Matrix (1 .. Width, 1 .. Height);
     for X in 1 .. Width loop
        for Y in 1 .. Height loop
           if Color_Random.Random (Color_Gen) = Black then
              Result.Values (X, Y) := (R => 0, G => 0, B => 0, A => 0);
           else
              Result.Values (X, Y) := (R => 255, G => 255, B => 255, A => 0);
           end if;
        end loop;
     end loop;
     return Result;
  end Create_Image;

end Noise;</lang>

test_noise.adb: <lang Ada>with Ada.Calendar; with Ada.Text_IO; with System.Address_To_Access_Conversions; with Lumen.Window; with Lumen.Image; with Lumen.Events.Animate; with GL; with Noise;

procedure Test_Noise is

  package Float_IO is new Ada.Text_IO.Float_IO (Float);
  Program_End : exception;
  Win : Lumen.Window.Handle;
  Image : Lumen.Image.Descriptor;
  Tx_Name : aliased GL.GLuint;
  Wide : Natural := 320;
  High : Natural := 240;
  First_Frame : Ada.Calendar.Time;
  Frame_Count : Natural := 0;
  -- Create a texture and bind a 2D image to it
  procedure Create_Texture is
     use GL;
     package GLB is new System.Address_To_Access_Conversions (GLubyte);
     IP : GLpointer;
  begin  -- Create_Texture
     -- Allocate a texture name
     glGenTextures (1, Tx_Name'Unchecked_Access);
     -- Bind texture operations to the newly-created texture name
     glBindTexture (GL_TEXTURE_2D, Tx_Name);
     -- Select modulate to mix texture with color for shading
     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     -- Wrap textures at both edges
     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
     -- How the texture behaves when minified and magnified
     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
     glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     -- Create a pointer to the image.  This sort of horror show is going to
     -- be disappearing once Lumen includes its own OpenGL bindings.
     IP := GLB.To_Pointer (Image.Values.all'Address).all'Unchecked_Access;
     -- Build our texture from the image we loaded earlier
     glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, GLsizei (Image.Width), GLsizei (Image.Height), 0,
                   GL_RGBA, GL_UNSIGNED_BYTE, IP);
  end Create_Texture;
  -- Set or reset the window view parameters
  procedure Set_View (W, H : in Natural) is
     use GL;
  begin  -- Set_View
     GL.glEnable (GL.GL_TEXTURE_2D);
     glClearColor (0.8, 0.8, 0.8, 1.0);
     glMatrixMode (GL_PROJECTION);
     glLoadIdentity;
     glViewport (0, 0, GLsizei (W), GLsizei (H));
     glOrtho (0.0, GLdouble (W), GLdouble (H), 0.0, -1.0, 1.0);
     glMatrixMode (GL_MODELVIEW);
     glLoadIdentity;
  end Set_View;
  -- Draw our scene
  procedure Draw is
     use GL;
  begin  -- Draw
     -- clear the screen
     glClear (GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
     GL.glBindTexture (GL.GL_TEXTURE_2D, Tx_Name);
     -- fill with a single textured quad
     glBegin (GL_QUADS);
     begin
        glTexCoord2f (1.0, 0.0);
        glVertex2i (GLint (Wide), 0);
        glTexCoord2f (0.0, 0.0);
        glVertex2i (0, 0);
        glTexCoord2f (0.0, 1.0);
        glVertex2i (0, GLint (High));
        glTexCoord2f (1.0, 1.0);
        glVertex2i (GLint (Wide), GLint (High));
     end;
     glEnd;
     -- flush rendering pipeline
     glFlush;
     -- Now show it
     Lumen.Window.Swap (Win);
  end Draw;
  -- Simple event handler routine for keypresses and close-window events
  procedure Quit_Handler (Event : in Lumen.Events.Event_Data) is
  begin  -- Quit_Handler
     raise Program_End;
  end Quit_Handler;
  -- Simple event handler routine for Exposed events
  procedure Expose_Handler (Event : in Lumen.Events.Event_Data) is
     pragma Unreferenced (Event);
  begin  -- Expose_Handler
     Draw;
  end Expose_Handler;
  -- Simple event handler routine for Resized events
  procedure Resize_Handler (Event : in Lumen.Events.Event_Data) is
  begin  -- Resize_Handler
     Wide := Event.Resize_Data.Width;
     High := Event.Resize_Data.Height;
     Set_View (Wide, High);
     Draw;
  end Resize_Handler;
  procedure Next_Frame (Frame_Delta : in Duration) is
     pragma Unreferenced (Frame_Delta);
     use type Ada.Calendar.Time;
  begin
     Frame_Count := Frame_Count + 1;
     if Ada.Calendar.Clock >= First_Frame + 1.0 then
        Ada.Text_IO.Put ("FPS: ");
        Float_IO.Put (Float (Frame_Count), 5, 1, 0);
        Ada.Text_IO.New_Line;
        First_Frame := Ada.Calendar.Clock;
        Frame_Count := 0;
     end if;
     Image := Noise.Create_Image (Width => Wide, Height => High);
     Create_Texture;
     Draw;
  end Next_Frame;

begin

  -- Create Lumen window, accepting most defaults; turn double buffering off
  -- for simplicity
  Lumen.Window.Create (Win           => Win,
                       Name          => "Noise fractal",
                       Width         => Wide,
                       Height        => High,
                       Events        => (Lumen.Window.Want_Exposure  => True,
                                         Lumen.Window.Want_Key_Press => True,
                                         others                      => False));
  -- Set up the viewport and scene parameters
  Set_View (Wide, High);
  -- Now create the texture and set up to use it
  Image := Noise.Create_Image (Width => Wide, Height => High);
  Create_Texture;
  First_Frame := Ada.Calendar.Clock;
  -- Enter the event loop
  declare
     use Lumen.Events;
  begin
     Animate.Select_Events (Win   => Win,
                            Calls => (Key_Press    => Quit_Handler'Unrestricted_Access,
                                      Exposed      => Expose_Handler'Unrestricted_Access,
                                      Resized      => Resize_Handler'Unrestricted_Access,
                                      Close_Window => Quit_Handler'Unrestricted_Access,
                                      others       => No_Callback),
                            FPS   => Animate.Flat_Out,
                            Frame => Next_Frame'Unrestricted_Access);
  end;

exception

  when Program_End =>
     null;

end Test_Noise;</lang>

C

Translation of: OCaml
Library: SDL

<lang c>#include <stdlib.h>

  1. include <stdio.h>
  2. include <time.h>
  3. include <SDL/SDL.h>

unsigned int frames = 0; unsigned int t_acc = 0;

void print_fps () {

 static Uint32 last_t = 0;
 Uint32 t = SDL_GetTicks();
 Uint32 dt = t - last_t;
 t_acc += dt;
 if (t_acc > 1000)
 {
   unsigned int el_time = t_acc / 1000;
   printf("- fps: %g\n",
           (float) frames / (float) el_time);
   t_acc = 0;
   frames = 0;
 }
 last_t = t;

}

void blit_noise(SDL_Surface *surf) {

 unsigned int i;
 long dim = surf->w * surf->h;
 while (1)
 {
   SDL_LockSurface(surf);
   for (i=0; i < dim; ++i) {
     ((unsigned char *)surf->pixels)[i] = ((rand() & 1) ? 255 : 0);
   }
   SDL_UnlockSurface(surf);
   SDL_Flip(surf);
   ++frames;
   print_fps();
 }

}

int main(void) {

 SDL_Surface *surf = NULL;
 srand((unsigned int)time(NULL));
 SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
 surf = SDL_SetVideoMode(320, 240, 8, SDL_DOUBLEBUF | SDL_HWSURFACE);
 blit_noise(surf);

}</lang>

Fast OpenGL method

Depending on your hardware, you might be able to get thousands of frames per second. Compiled with gcc -lglut -lGL -g -Wall -O2. <lang c>#include <GL/glut.h>

  1. include <GL/gl.h>
  2. include <stdio.h>
  3. include <time.h>
  1. define W 320
  2. define H 240
  3. define slen W * H / sizeof(int)

time_t start, last;

void render() { static int frame = 0, bits[slen]; register int i = slen, r; time_t t;

r = bits[0] + 1; while (i--) r *= 1103515245, bits[i] = r ^ (bits[i] >> 16);

glClear(GL_COLOR_BUFFER_BIT); glBitmap(W, H, 0, 0, 0, 0, (void*)bits); glFlush();

if (!(++frame & 15)) { if ((t = time(0)) > last) { last = t; printf("\rfps: %ld ", frame / (t - start)); fflush(stdout); } } }

int main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_INDEX); glutInitWindowSize(W, H); glutCreateWindow("noise"); glutDisplayFunc(render); glutIdleFunc(render);

last = start = time(0);

glutMainLoop(); return 0; }</lang>

C#

Max 185 FPS on .NET 4.0/Windows 7 64-bit on Athlon II X4 620 - ATI Radeon X1200.

<lang csharp>using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Drawing.Imaging; using System.Linq; using System.Runtime.InteropServices; using System.Windows.Forms;

class Program {

   static Size size = new Size(320, 240);
   static Rectangle rectsize = new Rectangle(new Point(0, 0), size);
   static int numpixels = size.Width * size.Height;
   static int numbytes = numpixels * 3;
   static PictureBox pb;
   static BackgroundWorker worker;
   static double time = 0;
   static double frames = 0;
   static Random rand = new Random();
   static byte tmp;
   static byte white = 255;
   static byte black = 0;
   static int halfmax = int.MaxValue / 2; // more voodoo! calling Next() is faster than Next(2)!
   static IEnumerable<byte> YieldVodoo()
   {
       // Yield 3 times same number (i.e 255 255 255) for numpixels times. 
       for (int i = 0; i < numpixels; i++)
       {
           tmp = rand.Next() < halfmax ? black : white; // no more lists!  
           // no more loops! yield! yield! yield!
           yield return tmp;
           yield return tmp;
           yield return tmp;
       }
   }
   static Image Randimg()
   {
       // Low-level bitmaps  
       var bitmap = new Bitmap(size.Width, size.Height);
       var data = bitmap.LockBits(rectsize, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
       Marshal.Copy(
           YieldVodoo().ToArray<byte>(),// source
           0, // start
           data.Scan0, // scan0 is a pointer to low-level bitmap data
           numbytes); // number of bytes in source
       bitmap.UnlockBits(data);
       return bitmap;
   }
   [STAThread]
   static void Main()
   {
       var form = new Form();
       form.AutoSize = true;
       form.Size = new Size(0, 0);
       form.Text = "Test";
       form.FormClosed += delegate
       {
           Application.Exit();
       };
       worker = new BackgroundWorker();
       worker.DoWork += delegate
       {
           System.Threading.Thread.Sleep(500); // remove try/catch, just wait a bit before looping
           while (true)
           {
               var a = DateTime.Now;
               pb.Image = Randimg();
               var b = DateTime.Now;
               time += (b - a).TotalSeconds;
               frames += 1;
               if (frames == 30)
               {
                   Console.WriteLine("{0} frames in {1:0.000} seconds. ({2:0} FPS)", frames, time, frames / time);
                   time = 0;
                   frames = 0;
               }
           }
       };
       worker.RunWorkerAsync();
       FlowLayoutPanel flp = new FlowLayoutPanel();
       form.Controls.Add(flp);
       pb = new PictureBox();
       pb.Size = size;
       flp.AutoSize = true;
       flp.Controls.Add(pb);
       form.Show();
       Application.Run();
   }

}</lang>

D

Translation of: C

<lang D>import std.stdio, std.random, sdl.SDL;

void main() {

 SDL_Init(SDL_INIT_TIMER | SDL_INIT_VIDEO);
 auto surface = SDL_SetVideoMode(320,240,8, SDL_DOUBLEBUF|SDL_HWSURFACE);
 uint frameNumber, totalTime, lastTime;
 while (true) {
   SDL_LockSurface(surface);
   foreach (i; 0 .. surface.w * surface.h)
     (cast(ubyte*)surface.pixels)[i] = (uniform(0, 2) ? 255 : 0);
   SDL_UnlockSurface(surface);
   SDL_Flip(surface);
   frameNumber++;
   uint time = SDL_GetTicks();
   totalTime += time - lastTime;
   if (totalTime > 1000) {
     writeln("FPS: ", frameNumber / (totalTime / 1000.0));
     totalTime = frameNumber = 0;
   }
   lastTime = time;
 }

}</lang> This D version shows about 155 FPS, while on the same PC the C version shows about 180 FPS.

Generating random bits with the C core.stdc.stdlib.rand the performance becomes about the same of the C version.

F#

This implementation includes two methods to update the pixels values. One uses unsafe methods and can do 350 fps on my machine, the second uses safe code to marshal the new values onto the bitmap data and can do 240 fps on the same machine. <lang fsharp>open System.Windows.Forms open System.Drawing open System.Drawing.Imaging open System.Runtime.InteropServices open System.Diagnostics open Microsoft.FSharp.NativeInterop

  1. nowarn "9"

let rnd = System.Random()

// Draw pixels using unsafe native pointer accessor. // This updates the bitmap as fast as possible. let drawbits_fast (size:int) (bits:BitmapData) =

   let mutable (p:nativeptr<byte>) = NativePtr.ofNativeInt(bits.Scan0)
   for n = 0 to size-1 do
       let c = rnd.Next(2) * 255
       NativePtr.set p 2 (byte c)
       NativePtr.set p 1 (byte c)
       NativePtr.set p 0 (byte c)
       NativePtr.set p 3 (byte 255)
       p <- NativePtr.add p 4

// A reasonably efficient updater using marshalling to copy an array of generated // integers onto the managed bitmap pixel data (see the C# example as well). let drawbits_safe (size:int) (bits:BitmapData) =

   let data = Array.init size (fun n ->
           let c = rnd.Next(2) * 255
           0xff000000 ||| (c <<< 16) ||| (c <<< 8) ||| c)
   Marshal.Copy(data, 0, bits.Scan0, size) |> ignore

// Create a new bitmap and update using the specified function let make_image (width:int) (height:int) f =

   let size = width * height
   let bmp = new Bitmap(width, height)
   let bits = bmp.LockBits(Rectangle(0,0,width,height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb)
   f size bits
   bmp.UnlockBits(bits)
   bmp

// Draw 30 frames and record the time and display the frames per second // This function is run asynchronously to avoid blocking the main GUI thread. let drawImage (box:PictureBox) (label:Label) f = async {

   while true do
       let timer = new Stopwatch()
       timer.Start()
       for frames = 0 to 29 do
           let bmp = make_image 320 240 f
           box.Image <- bmp
       timer.Stop()
       let fps = 30000. / timer.Elapsed.TotalMilliseconds
       label.Text <- sprintf "%.1f fps" fps }

[<System.STAThread>] [<EntryPoint>] let main args =

   let form = new Form(AutoSize=true,
                       Size=new Size(0,0),
                       Text="image noise demo")
   let panel = new FlowLayoutPanel(AutoSize=true,FlowDirection=FlowDirection.TopDown)
   let box = new PictureBox(AutoSize=true)
   let label = new Label(AutoSize=true, Text="Ready")
   form.FormClosed.Add(fun eventArgs -> Async.CancelDefaultToken()
                                        Application.Exit())
   form.Controls.Add(panel)
   panel.Controls.Add(box)
   panel.Controls.Add(label)
   if args.Length > 0 && args.[0] = "-safe" then
       drawImage box label drawbits_safe |> Async.Start
   else
       drawImage box label drawbits_fast |> Async.Start
   form.Show()
   Application.Run()
   0

</lang>

Factor

This example is in need of improvement:

This code may suck, please fix.

FPS does not show during execution on Linux, or on OpenBSD, until after closing the window. Forgot to flush the output stream?

  • Max 2 FPS on Factor 0.94 x86-64/Windows 7 64-bits - Athlon II X4 620 - ATI Radeon X1200.
  • 3 FPS on Factor 0.94 OpenBSD.

<lang factor>USING: namespaces ui ui.gadgets ui.gadgets.buttons ui.gadgets.tracks ui.gadgets.borders images images.viewer models timers accessors kernel sequences sequences.deep byte-vectors random calendar io math math.functions math.parser prettyprint debugger system ; FROM: models => change-model ;

IN: imagenoise

TUPLE: imgmodel < model content ; SYMBOL: dispimg SYMBOL: num SYMBOL: ttime

randimg ( -- img )
<image>
 { 320 240 } >>dim
 RGB >>component-order
 ubyte-components >>component-type
 dup dim>> product
 [ { 255 0 } random 3 swap <repetition> ] replicate flatten >byte-vector >>bitmap ;

randimg imgmodel new-model dispimg set-global 0 num set-global 0 ttime set-global

[

 now
 dispimg get-global
 [ drop randimg ] change-model
 num get-global 1 +
 num set-global

 now swap time- duration>seconds
 ttime get-global +  
 ttime set-global
 
 num get-global 10 <= 
  [ ]
  [
   num get-global 
   ttime get-global 
   [ / round number>string " FPS" append ] try print
   0 num set-global
   0 ttime set-global ] if  

] 1 nanoseconds every

[ vertical <track>

dispimg get-global <image-control> { 5 5 } <border> f track-add  
 
"Test" open-window

] with-ui</lang>

Go

<lang go>package main

import (

   "code.google.com/p/x-go-binding/ui/x11"
   "fmt"
   "image"
   "image/color"
   "image/draw"
   "log"
   "os"
   "time"

)

var randcol = genrandcol()

func genrandcol() <-chan color.Color {

   c := make(chan color.Color)
   go func() {
       for {
           select {
           case c <- image.Black:
           case c <- image.White:
           }
       }
   }()
   return c

}

func gennoise(screen draw.Image) {

   for y := 0; y < 240; y++ {
       for x := 0; x < 320; x++ {
           screen.Set(x, y, <-randcol)
       }
   }

}

func fps() chan<- bool {

   up := make(chan bool)
   go func() {
       var frames int64
       var lasttime time.Time
       var totaltime time.Duration
       for {
           <-up
           frames++
           now := time.Now()
           totaltime += now.Sub(lasttime)
           if totaltime > time.Second {
               fmt.Printf("FPS: %v\n", float64(frames)/totaltime.Seconds())
               frames = 0
               totaltime = 0
           }
           lasttime = now
       }
   }()
   return up

}

func main() {

   win, err := x11.NewWindow()
   if err != nil {
       fmt.Println(err)
       os.Exit(1)
   }
   defer win.Close()
   go func() {
       upfps := fps()
       screen := win.Screen()
       for {
           gennoise(screen)
           win.FlushImage()
           upfps <- true
       }
   }()
   for _ = range win.EventChan() {
   }

} </lang>

Optimized example

A second example that is somewhat more optimized but maybe more complicated. (~2900fps on a Thinkpad x220 laptop) <lang go>package main

/* Note, the x-go-binding/ui/x11 lib is under development and has as a temp solution

  set the x window to a static hight and with, you have to manualy set these
  to 240 x 320 in code.google.com/p/x-go-binding/ui/x11/conn.go */

import "code.google.com/p/x-go-binding/ui" import "code.google.com/p/x-go-binding/ui/x11" import "fmt" import "image" import "image/draw" import "io/ioutil" import "log" import "math/rand" import "regexp" import "runtime" import "strconv" import "time"

var frameCount uint64 var last time.Time var bw[65536][64]byte

func main() {

  // check how many physical cores that can be used
  tc := 1
  cpuInfoFile, err := ioutil.ReadFile("/proc/cpuinfo")
  if err == nil {
     regexpCores, err := regexp.Compile("cpu cores\t: [0-9]+")
     if err == nil {
        cpuInfoString := regexpCores.FindString(string(cpuInfoFile))
        tc, err = strconv.Atoi(cpuInfoString[12:])
        if err == nil {
           runtime.GOMAXPROCS(tc)
        }
     }
  }
  // Initiate a new x11 screen to print images onto
  win, err := x11.NewWindow()
  if err != nil {
     log.Fatalln(err)
  }
  defer win.Close()
  screen := win.Screen()
  _, ok := screen.(*image.RGBA)
  if !ok {
     log.Fatalln("screen isn't an RGBA image.")
  }
  //Create lookup table for every combination of 16 black/white pixels
  var i uint32
  for i = 0; i < 65536; i++ {
     if i & 0x0001 > 0  { bw[i][0]  = 0xFF; bw[i][1]  = 0xFF; bw[i][2]  = 0xFF; } // 00000000 00000001
     if i & 0x0002 > 0  { bw[i][4]  = 0xFF; bw[i][5]  = 0xFF; bw[i][6]  = 0xFF; } // 00000000 00000010
     if i & 0x0004 > 0  { bw[i][8]  = 0xFF; bw[i][9]  = 0xFF; bw[i][10] = 0xFF; } // 00000000 00000100
     if i & 0x0008 > 0  { bw[i][12] = 0xFF; bw[i][13] = 0xFF; bw[i][14] = 0xFF; } // 00000000 00001000
     if i & 0x0010 > 0  { bw[i][16] = 0xFF; bw[i][17] = 0xFF; bw[i][18] = 0xFF; } // 00000000 00010000
     if i & 0x0020 > 0  { bw[i][20] = 0xFF; bw[i][21] = 0xFF; bw[i][22] = 0xFF; } // 00000000 00100000
     if i & 0x0040 > 0  { bw[i][24] = 0xFF; bw[i][25] = 0xFF; bw[i][26] = 0xFF; } // 00000000 01000000
     if i & 0x0080 > 0  { bw[i][28] = 0xFF; bw[i][29] = 0xFF; bw[i][30] = 0xFF; } // 00000000 10000000
     if i & 0x0100 > 0  { bw[i][32] = 0xFF; bw[i][33] = 0xFF; bw[i][34] = 0xFF; } // 00000001 00000000
     if i & 0x0200 > 0  { bw[i][36] = 0xFF; bw[i][37] = 0xFF; bw[i][38] = 0xFF; } // 00000010 00000000
     if i & 0x0400 > 0  { bw[i][40] = 0xFF; bw[i][41] = 0xFF; bw[i][42] = 0xFF; } // 00000100 00000000
     if i & 0x0800 > 0  { bw[i][44] = 0xFF; bw[i][45] = 0xFF; bw[i][46] = 0xFF; } // 00001000 00000000
     if i & 0x1000 > 0  { bw[i][48] = 0xFF; bw[i][49] = 0xFF; bw[i][50] = 0xFF; } // 00010000 00000000
     if i & 0x2000 > 0  { bw[i][52] = 0xFF; bw[i][53] = 0xFF; bw[i][54] = 0xFF; } // 00100000 00000000
     if i & 0x4000 > 0  { bw[i][56] = 0xFF; bw[i][57] = 0xFF; bw[i][58] = 0xFF; } // 01000000 00000000
     if i & 0x8000 > 0  { bw[i][60] = 0xFF; bw[i][61] = 0xFF; bw[i][62] = 0xFF; } // 10000000 00000000
  }
  // Start one Go Thread per physical core + 1
  last = time.Now()
  for i := 0; i < tc; i++ {
      go createNoise(win, screen)
  }
  createNoise(win, screen)

}

func createNoise(win ui.Window, screen draw.Image) {

  var img [240 * 320 * 4]byte
  var rnd, rnd2, fps uint64
  var rnd16a, rnd16b, rnd16c, rnd16d uint16
  // Populate the image with pixel data
  for {
     for i := 0; i < len(img); i += 256 {
        rnd = uint64(rand.Int63())
        if (i % 63) == 0 {
           rnd2 = uint64(rand.Int63())
        }
        rnd |= rnd2 & 1 << 63 // we have to set the last bit from the int64 manualy
        rnd16a = uint16( rnd        & 0x000000000000FFFF)
        rnd16b = uint16((rnd >> 16) & 0x000000000000FFFF)
        rnd16c = uint16((rnd >> 32) & 0x000000000000FFFF)
        rnd16d = uint16((rnd >> 48) & 0x000000000000FFFF)
        copy(img[i    :i+ 64], bw[rnd16a][:])
        copy(img[i+ 64:i+128], bw[rnd16b][:])
        copy(img[i+128:i+192], bw[rnd16c][:])
        copy(img[i+192:i+256], bw[rnd16d][:])
        rnd2 = rnd2 >> 1 // rotate to next random bit
     }
     // Copy pixel data to the screen
     copy(screen.(*image.RGBA).Pix, img[:])
     win.FlushImage()
     // Fps counter
     frameCount++
     time.Sleep(1)
     if time.Since(last) >= time.Second {
        last = time.Now()
        fps = frameCount
        frameCount = 0
        fmt.Println("fps:", fps)
     }
  }

} </lang>

Icon and Unicon

Icon/Unicon provide a portable graphics interface that runs on multiple platforms. The frame rates will be lower than many of the other languages. There are several possible approaches to painting this random noise.

  • Using DrawPoint(c,r) for each pixel base on essentially a coin flip (speed ~= 1x)
  • Using DrawPoint!L on a list L := [c1,r1,c2,r2,...] of foreground pixels to be painted based on a coin flip (speed ~= 2x)
  • Using DrawImage to draw a randomly constructed bi-level images(see pg 157 of the graphics book, speed ~= 10x)

<lang Icon>link printf

procedure main()

  &window := open("B&W noise 320x240","g","size=320,240","bg=white","fg=black") | 
             stop("Open window failed ")
  runtime := 10 # seconds to run
  sec := &now
  frames := 0
  until (&now - sec) >= runtime do {
     s := "320,#"
     every 1 to 240 & 1 to 320/4 do s ||:= ?"0123456789ABCDEF" 
     DrawImage(0,0,s)
     frames +:= 1
     }
  sec := &now - sec 
  printf("frames=%d, elapsed time=%r, fps=%r\n",frames,sec, frames/real(sec))
  Event()   # wait for any window event
  close(&window)

end</lang>

printf.icn provides a family of print formatting routines

J

<lang j>coclass'example' (coinsert[require)'jzopengl'

P=: 0 : 0 pc p nosize; xywh 0 0 160 120;cc c isigraph opengl; pas 0 0;pcenter; rem form end;

pshow;
timer 1;

)

timestamp=: (6!:8) %~ 6!:9

create=:3 :0

 ogl=:conew'jzopengl'
 frames=:0
 start=: timestamp
 sys_timer_base_=: 1 :('p_c_paint_',(;coname),'_')
 wd P

)

p_run=: 3 : 0

 conew'example'

)

destroy=:3 :0

 end=:timestamp
 smoutput 'frames per second: ',":frames%end-start
 wd 'timer 0'
 destroy__ogl
 wd'pclose'
 codestroy

)

p_close=: destroy

p_c_paint=: 3 : 0

 rc__ogl
 glClear GL_COLOR_BUFFER_BIT
 glBegin GL_POINTS
   glVertex _1+2*53050 2?@$ 0
 glEnd
 show__ogl
 frames=:frames+1

)

p_run</lang>

The script auto-starts when run (that last line p_run'' is responsible for the auto-start.

Average FPS are displayed when the window is closed.

With this revision, on my laptop, I typically get in the range of 58..59 FPS, with a cpu load from J of about 3% (sometimes as much as 5%, sometimes as low as 0.1%). I am probably limited by v-sync, and (hypothetically speaking) if I tuned my opengl drivers I perhaps could get significantly faster fps. However, since my screen only refreshes approximately 60 times per second, anything over that would be meaningless.

About some of the constants: 160 120 corresponds to a 320 by 240 rendering area (this J version 6 mechanism will be obsolete soon, but I think we should wait for the new code bases stabilize before replacing this code), and the rendering area is not resizable. 53050 was picked because on average half of the pixels will be dark and half of them will be light: We have a black background and 53050 random pixel coordinates (out of 75800 total pixels) being set to being light -- because so many of them will randomly overlap we have on average approximately 50% of each. It would be more efficient to use a pixel shader, pushing the randomizing process into the graphics hardware. But, with this small of a display, efficiency is not really an issue with this approach.

Java

This could be done more concisely, but the version below features the following enhancements:

- Resizable window

- Real-time blurring of noise behind the FPS display

- Cycling through FPS display modes using mouse clicks

- Very fast: 1000+ FPS on a 2.8 GHz Core Duo (with 64-bit JRE). This is capped because the maximum resolution of the timers available is 1 ms <lang java>import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.util.Arrays; import java.util.Random; import javax.swing.*;

public class ImageNoise {

   int framecount = 0;
   int fps = 0;
   BufferedImage image;
   Kernel kernel;
   ConvolveOp cop;
   JFrame frame = new JFrame("Java Image Noise");
   JPanel panel = new JPanel() {
       private int show_fps = 0; // 0 = blur + FPS; 1 = FPS only; 2 = neither
       private MouseAdapter ma = new MouseAdapter() {
           @Override
           public void mouseClicked(MouseEvent e) {
               show_fps = (show_fps + 1) % 3;
           }
       };
       {addMouseListener(ma);} 
       @Override
       public Dimension getPreferredSize() {
           return new Dimension(320, 240);
       }
       @Override 
       @SuppressWarnings("fallthrough")
       public void paintComponent(Graphics g1) {
           Graphics2D g = (Graphics2D) g1;
           drawNoise();
           g.drawImage(image, 0, 0, null);
           switch (show_fps) {
           case 0: 
               // add blur behind FPS
               int xblur = getWidth() - 130, yblur = getHeight() - 32;
               BufferedImage bc = image.getSubimage(xblur, yblur, 115, 32);
               BufferedImage bs = new BufferedImage(bc.getWidth(), bc.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
               cop.filter(bc, bs);
               g.drawImage(bs, xblur, yblur , null);
           case 1: 
               // add FPS text; case fallthough is deliberate
               g.setColor(Color.RED);
               g.setFont(new Font("Monospaced", Font.BOLD, 20));
               g.drawString("FPS: " + fps, getWidth() - 120, getHeight() - 10);
           }
           framecount++;
       }
   };
   
   // Timer to trigger update display, with 1 ms delay
   Timer repainter = new Timer(1, new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           panel.repaint();
       }
   });
   
   // Timer to check FPS, once per second
   Timer framerateChecker = new Timer(1000, new ActionListener() {
       @Override
       public void actionPerformed(ActionEvent e) {
           fps = framecount;
           framecount = 0;
       }
   });
   
   public ImageNoise() {
       // Intitalize kernel describing blur, and convolve operation based on this
       float[] vals = new float[121];
       Arrays.fill(vals, 1/121f);
       kernel = new Kernel(11, 11, vals);
       cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
       
       // Initialize frame and timers
       frame.add(panel);
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       frame.pack();
       frame.setVisible(true);
       repainter.start();
       framerateChecker.start();
   }
   void drawNoise() {
       int w = panel.getWidth(), h = panel.getHeight();
       
       // Check if our image is null or window has been resized, requiring new image
       if (null == image || image.getWidth() != w || image.getHeight() != h) {
           image = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
       }
       Random rand = new Random();
       int[] data = new int[w * h];
       // Each int has 32 bits so we can use each bit for a different pixel - much faster
       for (int x = 0; x < w * h / 32; x++) {
           int r = rand.nextInt();
           for (int i = 0; i < 32; i++) {
               data[x * 32 + i] = (r & 1) * Integer.MAX_VALUE;
               r >>>= 1;
           }
       }
       // Copy raw data to the image's raster
       image.getRaster().setPixels(0, 0, w, h, data);
   }
   
   public static void main(String[] args) {
       // Invoke GUI on the Event Dispatching Thread
       SwingUtilities.invokeLater(new Runnable() {
           @Override
           public void run() {
               ImageNoise i = new ImageNoise();
           }
       });
   }

}</lang>

JavaScript

jsFiddle Demo

<lang javascript><body> <canvas id='c'></canvas>

<script> var canvas = document.getElementById('c'); var ctx = canvas.getContext('2d');

var w = canvas.width = 320; var h = canvas.height = 240; var t1 = new Date().getTime(); var frame_count = 0; ctx.font = 'normal 400 24px/2 Unknown Font, sans-serif'; var img = ctx.createImageData(w, h);

var index_init = 0; for (var x = 0; x < w; x++) {

   for (var y = 0; y < h; y++) {
       img.data[index_init + 3] = 255; // alpha
       index_init += 4;
   }

}

function animate() {

   var index = 0;
   for (var x = 0; x < w; x++) {
       for (var y = 0; y < h; y++) {
           var value = (Math.random() > 0.5) ? 255 : 0;
           img.data[index    ] = value;
           img.data[index + 1] = value;
           img.data[index + 2] = value;
           // alpha channel is constant
           index += 4;
       }
   }
   ctx.putImageData(img, 0, 0);
   frame_count++;
   if (frame_count % 50 == 0) {
       var fps = frame_count / (new Date().getTime() - t1) * 1000;
       window.status = fps.toFixed(2) + " fps";
   }
   setTimeout(animate, 0);

}

animate(); </script> </body></lang> About 59 frames/second on Firefox 4.

Liberty BASIC

Generates the random bitmap programmatically, then chops it each time in a different way. <lang lb> WindowWidth =411 w =320 WindowHeight =356 h =240


open "Noise" for graphics_nsb as #w

  1. w "trapclose [quit]"
  2. w "down"

print "Creating BMP header"

'bitmap header, 320x240 pixels 256 colors data 66,77,54,48,1,0,0,0,0,0,54,4,0,0,40,0,0,0,64,1 data 0,0,240,0,0,0,1,0,8,0,0,0,0,0,0,44,1,0,0,0 data 0,0,0,0,0,0,0,1,0,0,0,1,0,0

head$="" for i = 1 to 54

   read c
   head$=head$+chr$(c)

next

print "Creating BMP grayscale palette" pal$="" for i = 0 to 255

   pal$ = pal$ _
       + chr$(i) _
       + chr$(i) _
       + chr$(i) _
       + chr$(0)

next

print "Creating BMP random body"

   'create bitmap body
   body$=""
   for x =1 To w
       l$=""
       for y =1 To h
           l$=l$+chr$((rnd(1)>0.5)*255)
       next
       body$=body$+l$ 
   next

[main]

   scan
   ts =time$( "ms")
   'randomly "splice" the body: 1111222222-> 2222221111
   splice=int(len(body$)*rnd(1))+1
   body$= mid$(body$,splice+1)+left$(body$,splice)
   'write BMP
   open "noise.bmp" for output as #1
       #1 head$;pal$;
       #1 body$;
   close #1
   'load bmp
   loadbmp "noise", "noise.bmp"
   #w "cls"
   'drawbmp
   #w "drawbmp noise 0 0"
   tf =time$( "ms")
   dt =tf -ts
   if dt = 0 then dt = 1
   print "Framerate per second ="; using( "#.###", 1/(dt/1000)), "Ms per frame =";dt
   goto [main]

[quit]

   unloadbmp "noise"
   close #w

end </lang>

Mathematica

<lang Mathematica> time = AbsoluteTime[]; Animate[

Column[{Row[{"FPS: ", Round[n/(AbsoluteTime[] - time)]}], 
  RandomImage[1, {320, 240}]}], {n, 1, Infinity, 1}]

</lang>

OCaml

Library: OCamlSDL

with the ocaml-sdl bindings: <lang ocaml>let frames =

 { contents = 0 }

let t_acc =

 { contents = 0 }

let last_t =

 { contents = Sdltimer.get_ticks () }

let print_fps () =

 let t = Sdltimer.get_ticks () in
 let dt = t - !last_t in
 t_acc := !t_acc + dt;
 if !t_acc > 1000 then begin
   let el_time = !t_acc / 1000 in
   Printf.printf
     "- fps: %g\n%!"
     (float !frames /. float el_time);
   t_acc := 0;
   frames := 0;
 end;
 last_t := t

let blit_noise surf =

 let ba = Sdlvideo.pixel_data_8 surf in
 let dim = Bigarray.Array1.dim ba in
 while true do
   for i = 0 to pred dim do
     ba.{i} <- if Random.bool () then max_int else 0
   done;
   Sdlvideo.flip surf;
   incr frames;
   print_fps ()
 done

let blit_noise surf =

 try blit_noise surf
 with _ -> Sdl.quit ()

let () =

 Sdl.init [`VIDEO; `TIMER];
 Random.self_init();
 let surf =
   Sdlvideo.set_video_mode
     ~w:320 ~h:240 ~bpp:8
     [(*`HWSURFACE;*) `DOUBLEBUF]
 in
 Sys.catch_break true;
 blit_noise surf</lang>

compile to native-code with:

ocamlopt bigarray.cmxa -I +sdl sdl.cmxa noise_fps_sdl.ml -o noise_fps_sdl.opt

or using findlib:

ocamlfind opt -linkpkg -package sdl noise_fps_sdl.ml
./a.out

compile to bytecode with:

ocamlc bigarray.cma -I +sdl sdl.cma noise_fps_sdl.ml -o noise_fps_sdl.byte

In script mode, run with:

ocaml bigarray.cma -I +sdl sdl.cma noise_fps_sdl.ml

In a more idiomatic way, using the modules Graphics and Unix from the standard OCaml library: <lang ocaml>open Graphics

let white = (rgb 255 255 255) let black = (rgb 0 0 0)

let t_last = ref (Unix.gettimeofday())

let () =

 open_graph "";
 let width = 320
 and height = 240 in
 resize_window width height;
 try 
   while true do
     for y = 0 to pred height do
       for x = 0 to pred width do
         set_color (if Random.bool() then white else black);
         plot x y
       done;
     done;
     let t = Unix.gettimeofday() in
     Printf.printf "- fps: %f\n" (1.0 /. (t -. !t_last));
     t_last := t
   done
 with _ ->
   flush stdout;
   close_graph ()</lang>

run this script with:

ocaml unix.cma graphics.cma g.ml

And using an OCaml-Xlib bindings, or an OCaml-Allegro binding.


Equivalent of the C-OpenGL method.

PicoLisp

This solution works on ErsatzLisp, the Java version of PicoLisp. It creates a 'JFrame' window, and calls inlined Java code to handle the image. <lang PicoLisp>(javac "ImageNoise" "JPanel" NIL

     "java.util.*"
     "java.awt.*" "java.awt.image.*" "javax.swing.*" )
  int DX, DY;
  int[] Pixels;
  MemoryImageSource Source;
  Image Img;
  Random Rnd;
  public ImageNoise(int dx, int dy) {
     DX = dx;
     DY = dy;
     Pixels = new int[DX * DY];
     Source = new MemoryImageSource(DX, DY, Pixels, 0, DX);
     Source.setAnimated(true);
     Img = createImage(Source);
     Rnd = new Random();
  }
  public void paint(Graphics g) {update(g);}
  public void update(Graphics g) {g.drawImage(Img, 0, 0, this);}
  public void draw() {
     for (int i = 0; i < Pixels.length; ++i) {
        int c = Rnd.nextInt(255);
        Pixels[i] = 0xFF000000 | c<<16 | c<<8 | c;
     }
     Source.newPixels();
     paint(getGraphics());
  }

/**/

(de imageNoise (DX DY Fps)

  (let
     (Frame (java "javax.swing.JFrame" T "Image Noise")
        Noise (java "ImageNoise" T DX DY)
        Button (java "javax.swing.JButton" T "OK") )
     (java Frame "add" Noise)
     (java Frame "add" "South" Button)
     (java Button "addActionListener"
        (interface "java.awt.event.ActionListener"
           'actionPerformed '((Ev) (bye)) ) )
     (java Frame "setSize" DX DY)
     (java Frame "setVisible" T)
     (task (/ -1000 Fps) 0
        Image Noise
        (java Image "draw") ) ) )
  1. Start with 25 frames per second

(imageNoise 320 240 25)</lang>

PureBasic

<lang PureBasic>#filter=0.2  ; Filter parameter for the FPS-calculation

  1. UpdateFreq=100  ; How often to update the FPS-display

OpenWindow(0,400,300,320,240,"PureBasic") Define w=WindowWidth(0), h=WindowHeight(0) Define x, y, T, TOld, FloatingMedium.f, cnt InitSprite() OpenWindowedScreen(WindowID(0),0,0,w,h,1,0,0,#PB_Screen_NoSynchronization) Repeat

 StartDrawing(ScreenOutput())
 For y=0 To h-1
   For x=0 To w-1
     If Random(1)
       Plot(x,y,#Black)
     Else
       Plot(x,y,#White)
     EndIf
   Next
 Next
 StopDrawing()
 FlipBuffers()
 cnt+1
 If cnt>=#UpdateFreq
   cnt =0
   TOld=T
   T   =ElapsedMilliseconds()
   FloatingMedium*(1-#filter)+1000*#filter/(T-TOld)
   SetWindowTitle(0,"PureBasic: "+StrF(#UpdateFreq*FloatingMedium,2)+" FPS")
   Repeat ; Handle all events
     Event=WindowEvent()
     If Event=#PB_Event_CloseWindow
       End
     EndIf
   Until Not Event
 EndIf

ForEver</lang>

Python

Library: Tkinter
Library: PIL

<lang python>import time import random import Tkinter import Image, ImageTk # PIL libray

class App(object):

   def __init__(self, size, root):
       self.root = root
       self.root.title("Image Noise Test")
       self.img = Image.new("RGB", size)
       self.label = Tkinter.Label(root)
       self.label.pack()
       self.time = 0.0
       self.frames = 0
       self.size = size
       self.loop()
   def loop(self):
       self.ta = time.time()
       # 13 FPS boost. half integer idea from C#.
       rnd = random.random
       white = (255, 255, 255)
       black = (0, 0, 0)
       npixels = self.size[0] * self.size[1]
       data = [white if rnd() > 0.5 else black for i in xrange(npixels)]
       self.img.putdata(data)
       self.pimg = ImageTk.PhotoImage(self.img)
       self.label["image"] = self.pimg
       self.tb = time.time()
       self.time += (self.tb - self.ta)
       self.frames += 1
       if self.frames == 30:
           try:
               self.fps = self.frames / self.time
           except:
               self.fps = "INSTANT"
           print ("%d frames in %3.2f seconds (%s FPS)" %
                 (self.frames, self.time, self.fps))
           self.time = 0
           self.frames = 0
       self.root.after(1, self.loop)

def main():

   root = Tkinter.Tk()
   app = App((320, 240), root)
   root.mainloop()

main()</lang> About 28 FPS max, Python 2.6.6.

Ruby

Library: rubygems
Library: ruby-opengl

<lang ruby>require 'rubygems' require 'gl' require 'glut'

W, H = 320, 240 SIZE = W * H

Glut.glutInit ARGV Glut.glutInitWindowSize W, H

Glut.glutIdleFunc lambda {

 i = Time.now
 noise = (1..SIZE).map { rand > 0.5 ? 0xFFFFFFFF : 0xFF000000 }.pack("I*")
 Gl.glClear Gl::GL_COLOR_BUFFER_BIT
 Gl.glDrawPixels W, H, Gl::GL_RGBA, Gl::GL_UNSIGNED_BYTE, noise
 Gl.glFlush
 puts 1.0 / (Time.now - i)

}

Glut.glutCreateWindow "noise" Glut.glutMainLoop</lang>


Run BASIC

<lang runbasic>begSec = time$("seconds") graphic #g, 320,240 tics = 320 * 240 for i = 1 to tics

   x = int((rnd(1) * 320) + 1) 
   y = int((rnd(1) * 240) + 1)
   if int(x mod 2) then  #g "color black ; set "; x; " "; y else #g "color white ; set "; x; " "; y

next i endSec = time$("seconds") totSec = endSec - begSec print "Seconds;";totSec;" Count:";tics;" Tics / sec:";tics/totSec;" fps:";1/totSec render #g

  1. g "flush"</lang>

Scala

This is basically the same as the Java version, except without using BufferedImage. <lang scala> import java.awt.event.{ActionEvent, ActionListener} import swing.{Panel, MainFrame, SimpleSwingApplication} import javax.swing.Timer import java.awt.{Font, Color, Graphics2D, Dimension}

object ImageNoise extends SimpleSwingApplication {

 var delay_ms = 2
 var framecount = 0
 var fps = 0
 def top = new MainFrame {
   contents = panel
 }
 val panel = new Panel {
   preferredSize = new Dimension(320, 240)
   override def paintComponent(g: Graphics2D) {
     for (x <- 0 to size.width; y <- 0 to size.height) {
       val c = if (math.random > 0.5) Color.BLACK else Color.WHITE
       g.setColor(c)
       g.fillRect(x, y, 1, 1)
     }
     g.setColor(Color.RED)
     g.setFont(new Font("Monospaced", Font.BOLD, 20))
     g.drawString("FPS: " + fps, size.width - 100, size.height - 10)
     framecount += 1
   }
 }
 val repainter = new Timer(delay_ms, new ActionListener {
   def actionPerformed(e: ActionEvent) {
     panel.repaint
   }
 })
 val framerateChecker = new Timer(1000, new ActionListener {
   def actionPerformed(e: ActionEvent) {
     fps = framecount
     framecount = 0
   }
 })
 repainter.start()
 framerateChecker.start()

}</lang>

Tcl

Library: Tk

<lang tcl>package require Tk

proc generate {img width height} {

   set data {}
   for {set i 0} {$i<$height} {incr i} {

set line {} for {set j 0} {$j<$width} {incr j} { lappend line [lindex "#000000 #FFFFFF" [expr {rand() < 0.5}]] } lappend data $line

   }
   $img put $data

}

set time 0.0 set count 0

proc looper {} {

   global time count
   set t [lindex [time {generate noise 320 240}] 0]
   set time [expr {$time + $t}]
   if {[incr count] >= 30} {

set time [expr {$time / 1000000.0}] set fps [expr {$count / $time}] puts [format "%d frames in %3.2f seconds (%f FPS)" $count $time $fps] set time 0.0 set count 0

   }
   after 1 looper

}

image create photo noise -width 320 -height 240 pack [label .l -image noise] update looper</lang>

Visual Basic .NET

Some lines in this example are too long (more than 80 characters). Please fix the code if it's possible and remove this message.

Windows Forms Application.

<lang vbnet>Imports System.Drawing.Imaging

Public Class frmSnowExercise

 Dim bRunning As Boolean = True
 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
   ' Tell windows we want to handle all the painting and that we want it to double buffer
   ' the form's rectangle (Double Buffering removes/reduces flickering).
   SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer, True)
   UpdateStyles()
   ' Prevent the user from resizing the window. Our draw code is not
   ' setup to recalculate on the fly.
   FormBorderStyle = Windows.Forms.FormBorderStyle.FixedSingle
   MaximizeBox = False
   ' The window size and the client rectangle aren't the same.
   ' To get the proper dimensions for our exercise we need to 
   ' figure out the difference and add it to our 320x240 
   ' requirement.
   Width = 320 + Size.Width - ClientSize.Width
   Height = 240 + Size.Height - ClientSize.Height
   ' Pop the window, bring it to the front and give windows time to 
   ' reflect the changes.
   Show()
   Activate()
   Application.DoEvents()
   ' Hit the loop and keep going until we receive a close request.
   RenderLoop()
   ' We're done. Exit the application.
   Close()
 End Sub
 Private Sub Form1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
   ' Close the application when the user hits escape.
   If e.KeyChar = ChrW(Keys.Escape) Then bRunning = False
 End Sub
 Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
   ' We'll cancel the form close request if we're still running so we don't get an error during runtime and set the close request flag.
   e.Cancel = bRunning
   bRunning = False
 End Sub
 Private Sub RenderLoop()
   Const cfPadding As Single = 5.0F
   Dim b As New Bitmap(ClientSize.Width, ClientSize.Width, PixelFormat.Format32bppArgb)
   Dim g As Graphics = Graphics.FromImage(b)
   Dim r As New Random(Now.Millisecond)
   Dim oBMPData As BitmapData = Nothing
   Dim oPixels() As Integer = Nothing
   Dim oBlackWhite() As Integer = {Color.White.ToArgb, Color.Black.ToArgb}
   Dim oStopwatch As New Stopwatch
   Dim fElapsed As Single = 0.0F
   Dim iLoops As Integer = 0
   Dim sFPS As String = "0.0 FPS"
   Dim oFPSSize As SizeF = g.MeasureString(sFPS, Font)
   Dim oFPSBG As RectangleF = New RectangleF(ClientSize.Width - cfPadding - oFPSSize.Width, cfPadding, oFPSSize.Width, oFPSSize.Height)
   ' Get ourselves a nice, clean, black canvas to work with.
   g.Clear(Color.Black)
   ' Prep our bitmap for a read.
   oBMPData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)
   ' Allocate sufficient space for the pixel data and 
   ' flash copy it to our array.
   ' We want an integer to hold the color for each pixel in the canvas.
   Array.Resize(oPixels, b.Width * b.Height)
   Runtime.InteropServices.Marshal.Copy(oBMPData.Scan0, oPixels, 0, oPixels.Length)
   b.UnlockBits(oBMPData)
   ' Start looping.
   Do
     ' Find our frame time and add it to the total amount of time 
     ' elapsed since our last FPS update (once per second).
     fElapsed += oStopwatch.ElapsedMilliseconds / 1000.0F
     oStopwatch.Reset()
     oStopwatch.Start()
     ' Adjust the number of loops since the last whole second has elapsed.
     iLoops += 1
     If fElapsed >= 1.0F Then
       ' Since we've now had a whole second elapse
       ' figure the Frames Per Second, 
       ' measure our string,
       ' setup our backing rectangle for the FPS string (so it's clearly visible over the snow)
       ' reset our loop counter 
       ' and our elapsed counter.
       sFPS = (iLoops / fElapsed).ToString("0.0") & " FPS"
       oFPSSize = g.MeasureString(sFPS, Font)
       oFPSBG = New RectangleF(ClientSize.Width - cfPadding - oFPSSize.Width, cfPadding, oFPSSize.Width, oFPSSize.Height)
       fElapsed -= 1.0F ' We don't set this to 0 incase our frame time has gone a bit over 1 second since last update.
       iLoops = 0
     End If
     ' Generate our snow.
     For i As Integer = 0 To oPixels.GetUpperBound(0)
       oPixels(i) = oBlackWhite(r.Next(oBlackWhite.Length))
     Next
     ' Prep the bitmap for an update.
     oBMPData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb)
     ' Flash copy the new data into our bitmap.
     Runtime.InteropServices.Marshal.Copy(oPixels, 0, oBMPData.Scan0, oPixels.Length)
     b.UnlockBits(oBMPData)
     ' Draw the backing for our FPS display.
     g.FillRectangle(Brushes.Black, oFPSBG)
     ' Draw our FPS.
     g.DrawString(sFPS, Font, Brushes.Yellow, oFPSBG.Left, oFPSBG.Top)
     ' Update the form's background and draw.
     BackgroundImage = b
     Invalidate(ClientRectangle)
     ' Let windows handle some queued events.
     Application.DoEvents()
   Loop While bRunning
 End Sub

End Class</lang> Sample: