Example projects

Some examples to demonstrate Detroit engine in action. Although some of the examples can be used as a standalone applications, their primary purpose is just to demonstrate the engine and nothing more.

  1. Vesmir is artificial universe simulation. It generates a galaxy and about ten thousand stars in it. Some stars have planets to form solar systems, where some planets has moons as their companion. All the stars and planet images are modeled in realtime based on their chemical composition, so the outlook of the objects are quite close how they would look in reality. Vesmir example demonstrates drawing operations, menues, some of the widgets how they interact with window, and how to bind own C functions to Ano script.

  2. Deskmenu is a small desktop app launcher. Menu pops up by pressing middle mouse button, or alternatively keep ctrl key pressed while pressing the left mouse button. Deskmenu example demonstrates how to attach menu to widget and how to call external command in widget callback function, as well how to set some window attributes, like borderless and keep-above.

  3. Julia draws a Julia set in little window. Julia example demonstrates how to spawn a thread for drawing and do some RPN expressions to plot the pixels to window.

  4. Mandelbrot pretty much the same as Julia example above but draws a Mandelbrot set.

  5. Widgets example is nice looking but obsolete application just for playing and getting touch with most of the widgets. Widgets example demonstrates how to use different type of widgets and their attributes.

Example snippets

Some small Ano script snippets to demonstrate how to get various things done. See engine operands reference for detailed explanations for each function.

Audible white noise

Example how to generate white noise and play it.

main [exit: 0] {
	; Initialize audio system...
	;
	audio_init (\
		cb_track_play:		NULL, \
		cb_track_mode:		NULL, \
		cb_track_finish:	NULL, \
		cb_track_restart:	NULL, \
		cb_track_cancel:	NULL, \
		cb_track_pan:		NULL, \
		cb_track_vol:		NULL, \
		cb_master_vol:		NULL, \
		cb_buffer_start:	NULL, \
		cb_buffer_done:		NULL)

	; ...then generate 5 seconds of white noise and play it
	;
	_hnd = audio_create_noise_white (seconds: 5.0)

	if _hnd == 0 : error

	_hnd.play(volume: 1.0, pan: 0.0)
	_hnd.wait()
	_hnd.eject()

error:

}

Audible random wave

Example how to generate random wave and play it.

main [exit: 0] {
	; Initialize audio system...
	;
	audio_init (\
		cb_track_play:		NULL, \
		cb_track_mode:		NULL, \
		cb_track_finish:	NULL, \
		cb_track_restart:	NULL, \
		cb_track_cancel:	NULL, \
		cb_track_pan:		NULL, \
		cb_track_vol:		NULL, \
		cb_master_vol:		NULL, \
		cb_buffer_start:	NULL, \
		cb_buffer_done:		NULL)

	; ...then generate 5 second 440Hz (average) random wave using
	; amplitude of 1.0 and play it, sounds a bit like when sitting
	; in aeroplane
	;
	_hnd = audio_create_wave_random (\
		seconds: 5.0, \
		frequency: FREQ_A4, \
		amplitude: 1.0)

	if _hnd == 0 : error

	_hnd.play(volume: 1.0, pan: 0.0)
	_hnd.wait()
	_hnd.eject()

error:

}

Audible sine wave

Example how to generate sine wave and play it.

main [exit: 0] {
	; Initialize audio system...
	;
	audio_init (\
		cb_track_play:		NULL, \
		cb_track_mode:		NULL, \
		cb_track_finish:	NULL, \
		cb_track_restart:	NULL, \
		cb_track_cancel:	NULL, \
		cb_track_pan:		NULL, \
		cb_track_vol:		NULL, \
		cb_master_vol:		NULL, \
		cb_buffer_start:	NULL, \
		cb_buffer_done:		NULL)

	; ...then generate 5 second 262Hz sine wave and play it
	;
	_hnd = audio_create_wave_sine (\
		seconds: 5.0, \
		frequency: FREQ_MIDDLE_C)

	if _hnd == 0 : error

	_hnd.play(volume: 1.0, pan: 0.0)
	_hnd.wait()
	_hnd.eject()

error:

}

Audible square wave

Example how to generate square wave and play it.

main [exit: 0] {
	; Initialize audio system...
	;
	audio_init (\
		cb_track_play:		NULL, \
		cb_track_mode:		NULL, \
		cb_track_finish:	NULL, \
		cb_track_restart:	NULL, \
		cb_track_cancel:	NULL, \
		cb_track_pan:		NULL, \
		cb_track_vol:		NULL, \
		cb_master_vol:		NULL, \
		cb_buffer_start:	NULL, \
		cb_buffer_done:		NULL)

	; ...then generate 5 second 440Hz square wave and play it
	;
	_hnd = audio_create_wave_square (\
		seconds: 5.0, \
		frequency: FREQ_A4)

	if _hnd == 0 : error

	_hnd.play(volume: 1.0, pan: 0.0)
	_hnd.wait()
	_hnd.eject()

error:

}

Audio file

Example how to play audio file.

main [exit: 0] {
	; Initialize audio system...
	;
	audio_init (\
		cb_track_play:		NULL, \
		cb_track_mode:		NULL, \
		cb_track_finish:	NULL, \
		cb_track_restart:	NULL, \
		cb_track_cancel:	NULL, \
		cb_track_pan:		NULL, \
		cb_track_vol:		NULL, \
		cb_master_vol:		NULL, \
		cb_buffer_start:	NULL, \
		cb_buffer_done:		NULL)

	; ...then open audio file and play it
	;
	_hnd = audio_open_file (file: "audio_file.flac")

	if _hnd == 0 : error

	_hnd.play(volume: 1.0, pan: 0.0)
	_hnd.wait()
	_hnd.eject()

error:

}

Draw simple primitives

Example how to draw simple primitives to window.

main {
	; Global pre-initialized variables
	;
	mov	color ("cyanwhite")
	mov	color_alpha (# 0xe0, 0xff, 0xff, 0x80)

	; Initialize windowing system...
	;
	window_init

	; ...and open main window
	;
	window_open (\
		title_name:		"Drawing window", \
		title_charset:		NULL, \
		parent_handle:		NOPARENT, \
		widget_stack_id:	0, \
		widget_set:		0, \
		window_refresh_divider:	ACTIVE_REFRESH, \
		position_x:		POS_CENTERED, \
		position_y:		POS_CENTERED, \
		size_width:		600, \
		size_height:		300, \
		cb_main_loop:		"cb_mainloop", \
		cb_expose:		NULL, \
		cb_key_press:		"cb_keypress", \
		cb_key_release:		"cb_keyrelease", \
		cb_button_press:	"cb_buttonpress", \
		cb_button_release:	"cb_buttonrelease", \
		cb_client_message:	NULL, \
		cb_save_yourself:	NULL, \
		cb_configure_notify:	NULL, \
		cb_destroy_notify:	"cb_destroy", \
		cb_motion_notify:	"cb_motion", \
		cb_map_notify:		NULL, \
		cb_unmap_notify:	NULL, \
		cb_open_notify:		"cb_open")
}

_WINCB_MAINLOOP_ callback cb_mainloop_main (_hnd) {
	draw_wipe (_hnd)

	draw_pixel (_hnd, 10, 10, color)
	draw_pixel_alpha (_hnd, 20, 10, color_alpha)

	draw_subpixel (_hnd, 10, 20, color)
	draw_subpixel_alpha (_hnd, 20, 20, color_alpha)

	draw_set (_hnd, 10, 80, 20, 90, color)
	draw_set_alpha (_hnd, 30, 80, 40, 90, color_alpha)

	draw_border (_hnd, 10, 100, 10, 10, 1, color)
	draw_border_alpha (_hnd, 30, 100, 10, 10, 3, color_alpha)

	draw_copy (_hnd, 10, 10, 300, 10, 50, 50)
}

_WINCB_OPEN_ callback cb_open (_hnd) {
	_hnd.map()
}

_WINCB_DESTROY_ callback cb_destroy (_hnd) {
	_hnd.destroy()

	exit
}

_WINCB_KEY_ callback cb_keypress (hnd, x, y, x_root, y_root, state, keycode, key) {
}

_WINCB_KEY_ callback cb_keyrelease (hnd, x, y, x_root, y_root, state, keycode, key) {
}

_WINCB_BUTTON_ callback cb_buttonpress (hnd, x, y, x_root, y_root, state, button) {
}

_WINCB_BUTTON_ callback cb_buttonrelease (hnd, x, y, x_root, y_root, state, button) {
}

_WINCB_MOTION_ callback cb_motion (hnd, x, y, x_root, y_root, state, detail) {
}

Draw moving block

Example how to draw mouse-following block to window.

main {
	; Global pre-initialized variables
	;
	mov	color ("cyanwhite")

	mov	pos_x ([int] 0)
	mov	pos_y ([int] 0)
	mov	set_w ([int] 64)
	mov	set_h ([int] 64)

	; Initialize windowing system...
	;
	window_init

	; ...and open main window
	;
	window_open (\
		title_name:		"Drawing window", \
		title_charset:		NULL, \
		parent_handle:		NOPARENT, \
		widget_stack_id:	0, \
		widget_set:		0, \
		window_refresh_divider:	ACTIVE_REFRESH, \
		position_x:		POS_CENTERED, \
		position_y:		POS_CENTERED, \
		size_width:		600, \
		size_height:		300, \
		cb_main_loop:		"cb_mainloop", \
		cb_expose:		NULL, \
		cb_key_press:		"cb_keypress", \
		cb_key_release:		"cb_keyrelease", \
		cb_button_press:	"cb_buttonpress", \
		cb_button_release:	"cb_buttonrelease", \
		cb_client_message:	NULL, \
		cb_save_yourself:	NULL, \
		cb_configure_notify:	NULL, \
		cb_destroy_notify:	"cb_destroy", \
		cb_motion_notify:	"cb_motion", \
		cb_map_notify:		NULL, \
		cb_unmap_notify:	NULL, \
		cb_open_notify:		"cb_open")
}

_WINCB_MAINLOOP_ callback cb_mainloop (_hnd) {
	; Clear window...
	;
	draw_wipe (_hnd)

	; ...and draw simple block where the pointer is
	;
	draw_set (_hnd, \
		pos_x, pos_y, pos_x + set_w, pos_y + set_h, color)
}

_WINCB_OPEN_ callback cb_open (_hnd) {
	_hnd.map()
}

_WINCB_DESTROY_ callback cb_destroy (_hnd) {
	_hnd.destroy()

	exit
}

_WINCB_KEY_ callback cb_keypress (hnd, x, y, x_root, y_root, state, keycode, key) {
}

_WINCB_KEY_ callback cb_keyrelease (hnd, x, y, x_root, y_root, state, keycode, key) {
}

_WINCB_BUTTON_ callback cb_buttonpress (hnd, x, y, x_root, y_root, state, button) {
}

_WINCB_BUTTON_ callback cb_buttonrelease (hnd, x, y, x_root, y_root, state, button) {
}

_WINCB_MOTION_ callback cb_motion (hnd, x, y, x_root, y_root, state, detail) {
	; Update block coordinates
	;
	mov	pos_x (x - (set_w / 2))
	mov	pos_y (y - (set_h / 2))
}

Colors

Example how to use some color related functions.

main [exit: 0] {
	; Global uninitialized variables
	;
	var	[color] color1
	var	[color] color2

	; Mix two colors together using factor 0.5
	;
	mov	color1 ("blue")
	mov	color2 (# 0xff, 0x00, 0x00, 0xff)

	color_mix (color1, color2, 0.5)
	mov	color1 (rc)
	dump	color1

	; Get complement color
	;
	color_complement (color1)
	mov	color1 (rc)
	dump	color1

	; Get brightness
	;
	color_brightness (color1)
	mov	color1 (rc)
	dump	color1
}

Coordinates

Example how to use some coordinate related functions.

main [exit: 0] {
	; Set initial points for interpolation
	;
	mov	point_1 (& -1.1, 0.0, 0.0)
	mov	point_2 (& -1.1, -0.75, 0.0)
	mov	point_3 (& 1.9, 0.75, 0.0)
	mov	point_4 (& 1.9, 0.0, 0.0)

	; Set interpolation point, bias and tension
	;
	mov	intp (0.0)
	mov	bias (0.0)
	mov	tension (0.0)

	; Loop for ten interpolation points
	;
	loop (mov i ([int] 0); i < 10; inc i) {
		coords_intp_hermite_x (point_1, point_2, point_3, point_4, \
			intp, bias, tension)

		mov	pos_x (rc)
		dump	pos_x

		coords_intp_hermite_y (point_1, point_2, point_3, point_4, \
			intp, bias, tension)

		mov	pos_y (rc)
		dump	pos_y

		add	intp (0.1)
	}
}

Images

Example how to use some image related functions.

main [exit: 0] {
	; Global uninitialized variables
	;
	var	[image] image

	; Read TGA image in and write it out using RGB format
	;
	image_read ("image_input.tga")
	cmp	rc (% 0)
	je	"error"

	mov	image (rc)
	dump	image

	image_write_rgb ("image_output.rgb", image)
	cmp	rc (0)
	jne	"error"

	print "All done!\n"

error:

}

Host info

Example how to show some info about underlying machine.

main [exit: 0] {
	; Global uninitialized variables
	var	[string] system
	var	[string] release
	var	[string] machine
	var	[string] hostname
	var	[string] username
	var	[string] groupname
	var	[string] homedir

	; Get the info
	;
	node_get_system
	mov	system (rc)
	dump	system

	node_get_release
	mov	release (rc)
	dump	release

	node_get_machine
	mov	machine (rc)
	dump	machine

	node_get_hostname
	mov	hostname (rc)
	dump	hostname

	node_get_username
	mov	username (rc)
	dump	username

	node_get_groupname
	mov	groupname (rc)
	dump	groupname

	node_get_homedir
	mov	homedir (rc)
	dump	homedir
}

Clock

Example how to use some clock related functions.

main [exit: 0] {
	; Global uninitialized variables
	;
	var	[number] ticks
	var	[number] new_multiplier
	var	[number] old_multiplier

	; Get system time in secs since epoch and set clock to that
	;
	time
	mov	time (rc)
	dump	time

	clock_set (time)

	; Get clock tick count
	;
	clock_get_ticks
	mov	ticks (rc)
	dump	ticks

	; Set clock multiplier to ten to make it run ten times faster
	;
	clock_set_multiplier (10)
	mov	old_multiplier (rc)
	dump	old_multiplier

	; Get current multiplier
	;
	clock_get_multiplier
	mov	new_multiplier (rc)
	dump	new_multiplier

	; Wait for a while to tick count to increase
	;
	sleep (2, 0)

	; Get clock tick count again
	;
	clock_get_ticks
	mov	ticks (rc)
	dump	ticks
}

Timer

Example how to set the timer.

main {
	; Set timer to trigger one second and two nanoseconds from now
	;
	timer (1, 2, "my_timer")

	if rc != 0 : error

	print "Lets wait for timer...\n"

error:

}

alarm my_timer [respawn: 5, repeat: 10] {
	; This timer spawns 10 times at 5 second interval
	;
	print "Hello from timer!\n"
}

Thread affinity

Example how to set a thread to run on certain CPU.

main [exit: 0] {
	print "Hello from main program!\n"

	thread_spawn ("Ted the Thread", "my_thread")

	; Take a nap while thread starts
	;
	sleep (2, 0)
}

thread my_thread {
	; First stick this thread to run on first CPU...
	;
	thread_affinity (1)

	print "Hello from thread!\n"

	; ...and then to run on all configured CPU's
	;
	thread_affinity (0)

	print "Hello again from thread!\n"
}

Thread creation

Example how to spawn thread to run concurrently with main program.

main [exit: 0] {
	print "Hello from main program!\n"

	thread_spawn ("Ted the Thread", "my_thread")

	; Take a nap while thread starts
	;
	sleep (2, 0)
}

thread my_thread {
	print "Hello from thread!\n"
}

System commands

Example how to call some system commands.

	fork
	mov	_pid (rc)

	; Parent process exits immediately...
	;
	cmp	_pid (0)
	jne	"parent"

	; ...and child process does all the work
	;
	mov	_cmd ("uname")

	sleep (1, 0)
	exec (_cmd, "-p", "-m", "-r")

	sleep (3, 0)
	system (_cmd)

	sleep (5, 0)

: "parent"
	exit

Remote listener

Example how to use remote operations.

main {
	;
	; This is main program, just start remote thread and let it handle
	; remote connections. Program terminates when "remote_end" label is
	; called (see below) or  is pressed.
	;

	remote_init
}

function remote_test [remote: allow] (param1, param2, param3) {
	;
	; To call this function remotely (set SECRET with -na switch):
	;
	;  $ telnet localhost 2109
	;    SECRET remote_test int:1 uint:2 float:3.3
	;
	; or by using remotetool:
	;
	;  $ echo 'remote_test 1 2 3' | ./engine/tools/remotetool -na SECRET
	;
	; End code returned to caller is the sum of params or -1 if error
	; occurs.
	;

	dump	param1
	dump	param2
	dump	param3

	end	(param1 + param2 + param3)
}

function remote_end [remote: allow] {
	;
	; To call this function remotely (set SECRET with -na switch):
	;
	; $ telnet localhost 2109
	;   SECRET remote_end
	;
	; or by using remotetool:
	;
	;  $ echo 'remote_end' | ./engine/tools/remotetool -na SECRET
	;
	; Exit code returned to caller is 123
	;

	exit	(123)
}

function remote_forbidden {
	;
	; This function cannot be run remotely, as there is no remote: allow
	; attribute.
	;
}

Copyright © 2024, Jani Salonen <salojan at goto10 piste co>. Piste is finnish word and means dot. All rights reserved.