summaryrefslogblamecommitdiffstats
path: root/owndisplay.c
blob: e789cf3ae83f847a9ac5322da3df8f603fab0afc (plain) (tree)



















































































































































































































































































































                                                                                                    
#define _GNU_SOURCE
#include <netinet/ip.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <assert.h>
#include <unistd.h>
#include <png.h>

#define QUEUE_LEN 1000
#define MSGSIZE (2 + 7 * 160)

#define DISPLAY_HOST "100.65.0.2"
#define DISPLAY_PORT 5005
#define DISPLAY_WIDTH 1920
#define DISPLAY_HEIGHT 1080

struct mmsghdr msg[QUEUE_LEN];
struct iovec iovec[QUEUE_LEN];
uint8_t bufs[QUEUE_LEN][MSGSIZE];
int send_next = 0;
int next = 0;
int pos = 0;

static void
setup(void)
{
	for (int i=0;i<QUEUE_LEN;i++) {
		iovec[i].iov_base = bufs[i];
		msg[i].msg_hdr.msg_iov = &iovec[i];
		msg[i].msg_hdr.msg_iovlen = 1;
		bufs[i][0] = 0x00;
		bufs[i][1] = 0x01;
	}
}

static void
flush_frame(void)
{
	if (pos == 0) return;
	iovec[next].iov_len = 2 + (pos * 7);
	if (++next == QUEUE_LEN) next = 0;
}


static void
set_pixel(uint16_t x, uint16_t y, uint8_t r, uint8_t b, uint8_t g)
{
	uint8_t *buf = bufs[next] + 2 + pos * 7;
	buf[0] = x & 0xff;
	buf[1] = (x >> 8) & 0xff;
	buf[2] = y & 0xff;
	buf[3] = (y >> 8) & 0xff;
	buf[4] = r;
	buf[5] = b;
	buf[6] = g;
	if (++pos == 160) {
		flush_frame();
		pos = 0;
	}
}

static void
blank_screen(void)
{
	for (int x=0;x<DISPLAY_WIDTH;x++) {
		for (int y=0;y<DISPLAY_HEIGHT;y++) {
			set_pixel(x, y, 0, 0, 0);
		}
	}
}

struct data_png {
	int width, height;
	png_byte color_type;
	png_byte bit_depth;
	png_structp png_ptr;
	png_infop info_ptr;
	int number_of_passes;
	png_bytep * row_pointers;
};

static struct data_png *
open_png(const char *pngname)
{
	char header[8];
	FILE *fp = fopen(pngname, "rb");
	struct data_png *d = malloc(sizeof(struct data_png));

	assert(fp);
	assert(d != NULL);

	fread(header, 1, 8, fp);
	assert(png_sig_cmp(header, 0, 8) == 0);
	d->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	assert(d->png_ptr);
	d->info_ptr = png_create_info_struct(d->png_ptr);
	assert(d->info_ptr);
	png_init_io(d->png_ptr, fp);
	png_set_sig_bytes(d->png_ptr, 8);
	png_read_info(d->png_ptr, d->info_ptr);
	d->width = png_get_image_width(d->png_ptr, d->info_ptr);
	d->height = png_get_image_height(d->png_ptr, d->info_ptr);
	d->color_type = png_get_color_type(d->png_ptr, d->info_ptr);
	d->bit_depth = png_get_bit_depth(d->png_ptr, d->info_ptr);

	d->number_of_passes = png_set_interlace_handling(d->png_ptr);
	png_read_update_info(d->png_ptr, d->info_ptr);

	d->row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * d->height);
	for (int y=0; y<d->height; y++)
		d->row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(d->png_ptr,d->info_ptr));

	png_read_image(d->png_ptr, d->row_pointers);

	fclose(fp);

	return d;
}

static void
draw_png(struct data_png *d, int x, int y)
{
	for (int sy=0; sy < d->height; sy++) {
		png_byte *row = d->row_pointers[sy];
		for (int sx=0; sx < d->width; sx++) {
			uint8_t *rbga = &row[sx*4];
			if (rbga[3] > 0)
				set_pixel(x+sx, y+sy, rbga[0], rbga[1], rbga[2]);
		}
	}
}

struct bb_info {
	int x;
	int y;
	int x1, y1, x2, y2;
	int move_x;
	int move_y;
	int rate;
	struct data_png *img;
	const char *imgfile;
};

static void
bb_init(struct bb_info *bb, struct data_png *img, int x, int y, int w, int h)
{
	bb->img = img;
	bb->x1 = x;
	bb->y1 = y;
	bb->x2 = w - img->width;
	bb->y2 = h - img->height;
	if (bb->x == -1) bb->x = (bb->x1 + bb->x2) / 2;
	if (bb->y == -1) bb->y = (bb->y1 + bb->y2) / 2;
}

static void
bb_draw(struct bb_info *bb)
{
	draw_png(bb->img, bb->x, bb->y);

	bb->x += bb->move_x;
	bb->y += bb->move_y;

	if (bb->x < bb->x1 || bb->x > bb->x2)
		bb->move_x *= -1;
	if (bb->y < bb->y1 || bb->y > bb->y2)
		bb->move_y *= -1;
}

struct bb_info images[] = {
	{
		.imgfile = "images/unicorn_cc.png",
		.move_x = 13,
		.move_y = -10,
		.x = -1,
		.y = -1,
	},
	{
		.imgfile = "images/windows_logo.png",
		.move_x = -8,
		.move_y = 3,
		.rate = 2,
		.x = -1,
		.y = -1,
	},
	{
		.imgfile = "images/spade.png",
		.move_x = 32,
		.move_y = -12,
		.x = 0,
		.y = 0,
	},
	{
		.imgfile = "images/dvdvideo.png",
		.move_x = 200,
		.move_y = 60,
		.rate = 5,
		.x = -1,
		.y = -1,
		.x = 1000,
		.y = 800,
	},
	{
		.imgfile = "images/hackaday.png",
		.move_x = 40,
		.move_y = 18,
		.rate = 3,
		.x = -1,
		.y = -1,
		.x = 500,
		.y = 800,
	},
	{}
};

static void
draw_frame(unsigned int frameno)
{
	for (struct bb_info *bb = &images[0];bb->img;bb++) {
		if (bb->rate && frameno % bb->rate != 0)
			continue;
		bb_draw(bb);
	}
	flush_frame();
}

static void
send_stuff(int fd)
{
	int retval;
	int len;
	int from = send_next;
	if (next == send_next) {
		next = 0;
		send_next = 0;
		return;
	} else if (next > send_next) {
		len = next - send_next;
	} else {
		len = QUEUE_LEN - send_next;
	}

	retval = sendmmsg(fd, &msg[from], len, 0);
	if (retval == -1) {
		perror("sendmmsg()");
		return;
	}

	send_next += retval;
	if (send_next >= QUEUE_LEN) send_next = 0;
	//printf("%d/%d messages sent from %d, continuing from %d\n", retval, len, from, send_next);
}

int
main(void)
{
	int sockfd;
	struct sockaddr_in addr;
	struct hostent *hp;

	for (struct bb_info *bb = &images[0];bb->imgfile;bb++) {
		bb_init(bb, open_png(bb->imgfile), 0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
	}

	setup();

	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1) {
		perror("socket()");
		exit(EXIT_FAILURE);
	}


	if ((hp = gethostbyname(DISPLAY_HOST)) == NULL) {
		return -1;
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(DISPLAY_PORT);
	addr.sin_addr.s_addr = *( u_long * ) hp->h_addr;

	if (connect(sockfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
		perror("connect()");
		exit(EXIT_FAILURE);
	}

	//blank_screen();
	unsigned int frame = 0;
	while (1) {
		//printf("draw_frame\n");
		draw_frame(frame++);
		int old = send_next;
		for (int i=0;i<25;i++) {
			send_stuff(sockfd);
			send_next = old;
			//usleep(15000);
		}
		send_stuff(sockfd);
		//usleep(15000);
		//break;
	}

	exit(0);
}