OpenGL Fonts / Text Rendering using Pango, GTK, and gtkglext

I recently ran up against what seems to be a common problem: what's the easiest way to render text in OpenGL?

I'm using gtkglext, so I have lots of great text handling available to me. Particularly, pango makes it very easy to get beautiful fonts. gtkglext even has some font examples in the source tree.

But none of them met my particular needs. I found the following while searching for a solution:
 
Boost Converter: 2V 73kHz 1 stage
Boost Converter: 2V 73kHz 1 stage
Simulated using Paul Falstad's Circuit Simulator

Solar Cells:
This circuit models a solar cell:
Solar Cell Model
download the model (modeled using Paul Falstad's Circuit Simulator)

Explanation: The current source + diode + resistor are a model of a solar cell. A perfect model would also have a shunt resistor in parallel with the current source and diode. The resistor in this model is the series resistance.

The fet is used as a varying resistance. It models a purely resistive load on the solar cell and with the sawtooth voltage source attached to it, it makes it easy to plot the power dissipated in the fet.

At the maximum power point, the fet's resistance draws exactly the right amount of current and voltage from the solar cell. The FF (fill factor) represents how much power (Watts) the fet can draw, as a percentage of the maximum possible power the cell can produce: 100mA * 3.3V = .33 Watts.

The Vg voltage from gate to source is where the sawtooth voltage source hits that maximum power point. Results tabulated show the maximum power point as a function of series resistance, showing that the FF is highest when the series resistance is minimized. This makes sense intuitively: the resistance is dissipating power, so minimizing it allows the maximum power to reach the fet.
www.noondaysystems.com FP-Accelerated Heap
Fixed-Time Dynamic Allocator Copyright © 1-Sept-2011

Reference gcc implementations are available for:
FIONREAD for File I/O

I've looked around for good documentation on how to write an app that uses FIONREAD in C/C++. You may want to start by reading tty_ioctl(4). Since I had a hard time finding example code (just this), I posted this.

FIONREAD: use this ioctl() to get the number of bytes available on a file descriptor. The bytes have already been received by the kernel, and are waiting in the input buffer.

Brief Usage:
#include <sys/ioctl.h>
#include <termios.h>
int n_bytes;
if (ioctl(fd, FIONREAD, &n_bytes) < 0) {
	/* handle error */
}

Supported in:

Example scenario: C/C++ app reading from a serial port.
The following sample app has been tested with a serial port. Other uses would include a co-process using the file descriptors returned from pipe(). (Note: setting up a serial port typically requires additional code not shown here, e.g. to set the baud rate.)

If you go directly to read() without doing FIONREAD first, you must read 1 byte at a time, and then use select() or pselect() again. FIONREAD offers much better performance.

It may be tempting to assume an entire line of input has been read when using FIONREAD to communicate using a line-based protocol (e.g. the AT command set). This can lead to bugs: always store the input in a buffer, then search the buffer for a newline ('\n') to identify a line of input. If you got a partial line, save it and wait for the rest, by looping back around to the select() or pselect().

Sample App: (Download fionread_example.c)
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

int write_to(const char * fname, int fd, const char * msg)
{
	const char * p = msg;
	int n_bytes = strlen(msg);
	while (n_bytes) {
		int r = write(fd, p, n_bytes);
		if (r < 0) {
			fprintf(stderr, "write %s failed: %d %s\n", fname, errno, strerror(errno));
			return 1;
		}
		if (r == 0) {
			// network sockets may return a 0-byte write; files never should
			fprintf(stderr, "write %s: unexpected network behavior\n", fname);
			return 1;
		}
		n_bytes -= r;
		p += r;
	}
	return 0;
}

const char uart_device[] = "/dev/ttyACM0";

int uart_connect(int fd)
{
	struct timeval t_start;
	gettimeofday(&t_start, 0 /*tz*/);
	int request_sent = 0, n_bytes;
	char buf[4096];

	while (1) {
		struct timespec t_out;
		struct timeval t_now;
		gettimeofday(&t_now, 0 /*tz*/);
		t_out.tv_nsec = (t_start.tv_usec - t_now.tv_usec + 1000000)*1000L;
		t_out.tv_sec = t_start.tv_sec - t_now.tv_sec;
		if (t_out.tv_nsec >= 1000000000L) {
			t_out.tv_nsec -= 1000000000L;
			t_out.tv_sec++;
		}

		fd_set rfds, wfds, efds;
		FD_ZERO(&rfds);
		FD_ZERO(&wfds);
		FD_ZERO(&efds);
		FD_SET(fd, &rfds);

		int r = pselect(fd + 1, &rfds, &wfds, &efds, &t_out, 0 /*sigmask*/);
		if (r == -1) {
			fprintf(stderr, "%s: pselect failed %d %s\n", uart_device, errno, strerror(errno));
			return 1;
		}
		if (r == 0) {
			if (request_sent) {
				// waited 1 s for response, time out
				fprintf(stderr, "timeout waiting for %s\n", uart_device);
				return 1;
			}

			// send request after waiting for 1 s
			request_sent = 1;

			if (write_to(uart_device, fd, "AT\n")) return 1;
			fprintf(stderr, "write AT\n");
			gettimeofday(&t_start, 0 /*tz*/);
		}

		if (FD_ISSET(fd, &rfds)) {
			if (ioctl(fd, FIONREAD, &n_bytes) < 0) {
				fprintf(stderr, "FIONREAD failed: %d %s\n", errno, strerror(errno));
				return 1;
			}
			if (n_bytes > (int) sizeof(buf)) n_bytes = (int) sizeof(buf);
			r = read(fd, buf, n_bytes);
			if (r < 0) {
				fprintf(stderr, "read %s failed: %d %s\n", uart_device, errno, strerror(errno));
				return 1;
			}
			buf[r] = 0;
			fprintf(stderr, "read %d bytes: \"%s\"\n", r, buf);
		}
	}

	return 0;
}

int main()
{
	int fd = open(uart_device, O_RDWR);
	if (fd == -1) {
		fprintf(stderr, "unable to connect: %d %s\n", errno, strerror(errno));
		return 1;
	}

	if (uart_connect(fd)) {
		close(fd);
		return 1;
	}

	close(fd);
	return 0;
}
pingraph.sh: Log-scale ping graph

This shell script runs ping and pretty-prints the output. Download

Tested on: ubuntu, fedora core, Mac OS X, gentoo

Sample output:
ping: sendto: No route to host
 71.107 ms ======ping: sendto: No route to host

--- 8.8.8.8 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 62.709/65.100/71.107/3.493 ms


The sample output shows how error messages are passed through. The source:
#!/bin/bash
if [ -z "$1" ]; then
	ping 2$gt;&1 | sed -e "s/ping/`basename $0`/g"
	exit 1
fi

signalpingchild()
{
	for a in 1 2 3 4; do ps -f $gt;/dev/null; done
}

trap signalpingchild INT TERM HUP QUIT

ping -s18 -n $1 | while read a; do
	[ "${a#PING $1}" != "$a" -o -z "$a" ] && continue
	if [ "${a%statistics ---}" != "$a" ]; then
		echo ""
		echo "$a"
		cat
		break
	fi
	if [ "${a/icmp_seq/}" == "$a" ]; then
		echo -ne "\r\e[K"
		echo "$a"
		continue
	fi
	v="`echo \"$a\" | awk '{ d=$4; sub(":\$", "", d); \
		t=$7; sub("^time=", "", t); \
		x=log(t) + 3; if (x $gt; 5) x = x*16 - 16*5; \
		print "b=" $1 "; d=\\\"" d "\\\"; " $6 "; t=\\\"" t "\\\"; x=" x "; s=\\\"" $8 "\\\""; \
	}'`"
	eval "$v"
	if [ $b -ne $((18+8)) -o "$d" != "$1" -o "$s" != "ms" ]; then
		echo "$a: bad $v"
		continue
	fi
	# pretty-print
	echo -ne '\r\e[K' | awk "{
		t=$t;
		if (t<1000) { u=\"m\" }
		else if (t<1000000) { u=\"\"; t /= 1000 };
		for (x=0; x<$x; x++) b=b \"=\";
		printf \"%s%7.3f %ss %s\", \$0, t, u, b;
		exit}"
done &
wait $! # this convinces ping it is connected to a tty
	
x86_64 Cross-Compiler for Macports / Darwin

Macports already has good cross-compilers for arm, i386, ppc, i960, and a few more. But there is not one yet for x86_64. Leaning heavily on Gentoo's crossdev script, here's a script to create a very basic bootstrap x86_64 gcc: cross-build.sh.

It looks for the following files in the same directory as cross-build.sh: If this seems like a confusing list, I apologize. It's the sources for a cross-compiler in gentoo. I've tested building the x86_64 cross-compiler on Darwin using these files: Please note however that the script is generic enough it should work fine with any set of source files. Gentoo's set is reasonably well tested, is all. (That turns out to be a big deal, because building a good cross-compiler is so non-trivial.)

Dell 3110cn Color Laser Printer - PPD driver for Linux

The file that used to be found at http://openprinting.org/show_printer.cgi?recnum=Dell-3110cn has been deleted. (No explanation why, cached results on search engines seem to indicate everyone thought that was the right place to go to find the driver for printing using Linux.)

I happened to download it, so here it is:

dell3110cn.ppd - 140 KB
Serial Pin Control in Linux
This utility allows you to read and write (get, set, or toggle) the individual pins on a serial port, such as RTS and DTR.
Download source code

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#define winsize __termios__winsize
#define termio __termios__termio
#include <linux/termios.h>

/*
* TIOCMSET and TIOCMGET are POSIX
* TIOCMODS and TIOCMODG are BSD (4.3 ?)
* MCSETA and MCGETA are HPUX
*/
int do_set(int fd, const char * bitstr, int bit, int on)
{
	if (bit == 0) {
		fprintf(stderr, "set(%s = %d): invalid bit\n", bitstr, on);
		return 1;
	}
	if (ioctl(fd, (on ? TIOCMBIS : TIOCMBIC), &bit)) {
		fprintf(stderr, "set(%s = %d) failed: %d %s\n", bitstr, on, errno, strerror(errno));
		return 1;
	}
	if (bit == TIOCM_CTS || bit == TIOCM_CAR || bit == TIOCM_RNG || bit == TIOCM_DSR)
		printf("set(%s = %d) warning: setting an input pin will be ignored\n", bitstr, on);
		else printf("set(%s = %d) success\n", bitstr, on);
	return 0;
}

int do_get(int fd, const char * bitstr, int bit, int quiet)
{
	int result;
	if (ioctl(fd, TIOCMGET, &result)) {
		fprintf(stderr, "get(%s) failed: %d %s\n", bitstr, errno, strerror(errno));
		return 1;
	}
	if (quiet) printf("%d", (result & bit) ? 1 : 0);
	else printf("%s = %d (%02x & %02x)\n", bitstr, (result & bit) ? 1 : 0, result, bit);
	return 0;
}

int getbit(const char * str)
{
	if (strcasecmp(str, "le") == 0) return TIOCM_LE;
	if (strcasecmp(str, "rts") == 0) return TIOCM_RTS;
	if (strcasecmp(str, "dtr") == 0) return TIOCM_DTR;
	if (strcasecmp(str, "st") == 0) return TIOCM_ST;
	if (strcasecmp(str, "sr") == 0) return TIOCM_SR;
	if (strcasecmp(str, "cts") == 0) return TIOCM_CTS;
	if (strcasecmp(str, "car") == 0) return TIOCM_CAR;
	if (strcasecmp(str, "cd") == 0) return TIOCM_CD;
	if (strcasecmp(str, "rng") == 0) return TIOCM_RNG;
	if (strcasecmp(str, "ri") == 0) return TIOCM_RI;
	if (strcasecmp(str, "dsr") == 0) return TIOCM_DSR;
	if (strcasecmp(str, "out1") == 0) return TIOCM_OUT1;
	if (strcasecmp(str, "out2") == 0) return TIOCM_OUT2;
	if (strcasecmp(str, "loop") == 0) return TIOCM_LOOP;
	return 0;
}

int main(int argc, char ** argv)
{
	if (argc != 3 && (argc != 4 || (argv[3][0] != '1' && argv[3][0] != '0' && strcmp(argv[3], "-q")))) {
		fprintf(stderr, "usage: %s dev pin [ 0 | 1 ]\n"
			"    pin 0 turns off pin, pin 1 turns on pin\n"
			"    pin without any argument reads its current state\n"
			"    add -q when reading to only output the bit\n"
			"        le: line enable (input, usually wired to dsr)\n"
			"        dtr: data terminal ready (output, dsr on other side)\n"
			"        rts: request to send (output, rts on other side)\n"
			"        st: secondary TXD (output)\n"
			"        sr: secondary RXD (output)\n"
			"        cts: clear to send (input, rts on other side)\n"
			"        car or cd: carrier detect (input)\n"
			"        rng or ri: ring indicator (input)\n"
			"        dsr: data set ready (input, dtr on other side)\n"
			"        out1: (output)\n"
			"        out2: (output)\n"
			"        loop: set loopback mode (for testing)\n", argv[0]);
		return 1;
	}
	int fd = open(argv[1], O_RDONLY);
	if (fd < 0) {
		fprintf(stderr, "failed to open \"%s\": %d %s\n", argv[1], errno, strerror(errno));
		return 1;
	}

	int r;
	if (argc == 4 && argv[3][0] != '-') r = do_set(fd, argv[2], getbit(argv[2]), argv[3][0] == '1' ? 1 : 0);
		else r = do_get(fd, argv[2], getbit(argv[2]), (argc == 4 && strcmp(argv[3], "-q") == 0));
	close(fd);
	return r;
}
	
Commander Keen Clone (Commander Genius) gentoo ebuild:
keengenius.git.ebuild.tar.bz2 (1.3KB)

smali and baksmali gentoo ebuild: baksmali-0.0.9999.ebuild (1K)