forked from scottyallen/flaschen-taschen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
udp-flaschen-taschen.cc
125 lines (110 loc) · 4.23 KB
/
udp-flaschen-taschen.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; -*-
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation version 2.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://gnu.org/licenses/gpl-2.0.txt>
//
//
// Our format has the same header and data as a P6 PPM format.
// However, we add an optional footer with offset_x and offset_y where
// to display the PPM image.
// This is to
// * be compatible with regular PPM: it can be read, but footer is ignored.
// * it couldn't have been put in the header, as that is already strictly
// defined to contain exactly three decimal numbers.
//
#include "udp-flaschen-taschen.h"
#include <assert.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <algorithm>
#define DEFAULT_FT_DISPLAY_HOST "ft.noise"
int OpenFlaschenTaschenSocket(const char *host) {
if (host == NULL) {
host = getenv("FT_DISPLAY"); // Take from environment.
}
if (host == NULL || strlen(host) == 0) {
host = DEFAULT_FT_DISPLAY_HOST; // Fallback.
}
struct addrinfo addr_hints = {0};
addr_hints.ai_family = AF_INET;
addr_hints.ai_socktype = SOCK_DGRAM;
struct addrinfo *addr_result = NULL;
int rc;
if ((rc = getaddrinfo(host, "1337", &addr_hints, &addr_result)) != 0) {
fprintf(stderr, "Resolving '%s': %s\n", host, gai_strerror(rc));
return -1;
}
if (addr_result == NULL)
return -1;
int fd = socket(addr_result->ai_family,
addr_result->ai_socktype,
addr_result->ai_protocol);
if (fd >= 0 &&
connect(fd, addr_result->ai_addr, addr_result->ai_addrlen) < 0) {
perror("connect()");
close(fd);
fd = -1;
}
freeaddrinfo(addr_result);
return fd;
}
// Let's have a fixed-size footer for fixed buffer calculation.
static const int kFooterLen = strlen("\n0001 0001 0001\n") + 1; // offsets.
UDPFlaschenTaschen::UDPFlaschenTaschen(int socket, int width, int height)
: fd_(socket), width_(width), height_(height) {
char header[64];
int header_len = snprintf(header, sizeof(header),
"P6\n%d %d\n255\n", width, height);
buf_size_ = header_len + width_ * height_ * sizeof(Color) + kFooterLen;
buffer_ = new char[buf_size_];
bzero(buffer_, buf_size_);
strcpy(buffer_, header);
pixel_buffer_start_ = reinterpret_cast<Color*>(buffer_ + header_len);
footer_start_ = buffer_ + buf_size_ - kFooterLen;
SetOffset(0, 0, 0);
}
UDPFlaschenTaschen::~UDPFlaschenTaschen() { delete [] buffer_; }
void UDPFlaschenTaschen::Clear() {
bzero(pixel_buffer_start_, width_ * height_ * sizeof(Color));
}
void UDPFlaschenTaschen::Fill(const Color &c) {
if (c.is_black()) {
Clear(); // cheaper
} else {
std::fill(pixel_buffer_start_, pixel_buffer_start_ + width_*height_, c);
}
}
void UDPFlaschenTaschen::SetOffset(int off_x, int off_y, int off_z){
// Our extension to the PPM format adds footers after the image data.
snprintf(footer_start_, kFooterLen, "\n%4d %4d %4d\n", off_x, off_y, off_z);
}
void UDPFlaschenTaschen::SetPixel(int x, int y, const Color &col) {
if (x < 0 || x >= width_ || y < 0 || y >= height_) return;
pixel_buffer_start_[x + y * width_] = col;
}
const Color &UDPFlaschenTaschen::GetPixel(int x, int y) {
return pixel_buffer_start_[(x % width_) + (y % height_) * width_];
}
void UDPFlaschenTaschen::Send(int fd) {
// Some fudging to make the compiler shut up about non-used return value
if (write(fd, buffer_, buf_size_) < 0) return;
}
UDPFlaschenTaschen* UDPFlaschenTaschen::Clone() const {
UDPFlaschenTaschen *result = new UDPFlaschenTaschen(fd_, width_, height_);
memcpy(result->buffer_, buffer_, buf_size_);
return result;
}