quakeforge/qw/source/cl_rss.c

244 lines
5.0 KiB
C

/*
cl_screen.c
master for refresh, status bar, console, chat, notify, etc
Copyright (C) 1996-1997 Id Software, Inc.
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; either version 2
of the License, or (at your option) any later version.
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, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <time.h>
#include "QF/dstring.h"
#include "QF/image.h"
#include "QF/pcx.h"
#include "QF/sys.h"
#include "qw/include/cl_parse.h"
#include "qw/include/client.h"
/*
Find closest color in the palette for named color
*/
static int
rgb_palette (int r, int g, int b, int bgr)
{
float bestdist, dist;
int r1, g1, b1, i;
int best = 0;
static int lastbest;
static int lr = -1, lg = -1, lb = -1;
if (bgr) {
int t = r;
r = b;
b = t;
}
if (r == lr && g == lg && b == lb)
return lastbest;
bestdist = 256 * 256 * 3;
for (i = 0; i < 256; i++) {
int j;
j = i * 3;
r1 = r_data->vid->palette[j] - r;
g1 = r_data->vid->palette[j + 1] - g;
b1 = r_data->vid->palette[j + 2] - b;
dist = r1 * r1 + g1 * g1 + b1 * b1;
if (dist < bestdist) {
bestdist = dist;
best = i;
}
}
lr = r;
lg = g;
lb = b;
lastbest = best;
return best;
}
static void
snap_drawchar (int num, byte *dest, int width)
{
byte *source;
int col, row, drawline, x;
row = num >> 4;
col = num & 15;
source = draw_chars + (row << 10) + (col << 3);
drawline = 8;
while (drawline--) {
for (x = 0; x < 8; x++)
if (source[x])
dest[x] = source[x];
else
dest[x] = 98;
source += 128;
dest -= width;
}
}
static void
snap_drawstring (const char *s, tex_t *tex, int x, int y)
{
byte *dest;
byte *buf = tex->data;
const byte *p;
int width = tex->width;
dest = buf + ((y * width) + x);
p = (const byte *) s;
while (*p) {
snap_drawchar (*p++, dest, width);
dest += 8;
}
}
static tex_t *
cruch_snap (tex_t *snap, unsigned width, unsigned height)
{
byte *src, *dest;
float fracw, frach;
unsigned count, dex, dey, dx, dy, nx, r, g, b, x, y, w, h;
tex_t *tex;
//FIXME casts
w = ((unsigned)snap->width < width) ? (unsigned)snap->width : width;
h = ((unsigned)snap->height < height) ? (unsigned)snap->height : height;
fracw = (float) snap->width / (float) w;
frach = (float) snap->height / (float) h;
tex = malloc (sizeof (tex_t) + w * h);
tex->data = (byte *) (tex + 1);
if (!tex)
return 0;
tex->width = w;
tex->height = h;
tex->flagbits = 0;
tex->loaded = 1;
tex->flipped = snap->flipped;
tex->palette = r_data->vid->palette;
for (y = 0; y < h; y++) {
dest = tex->data + (w * y);
for (x = 0; x < w; x++) {
r = g = b = 0;
dx = x * fracw;
dex = (x + 1) * fracw;
if (dex == dx)
dex++; // at least one
dy = y * frach;
dey = (y + 1) * frach;
if (dey == dy)
dey++; // at least one
count = 0;
for (; dy < dey; dy++) {
src = snap->data + (snap->width * 3 * dy) + dx * 3;
for (nx = dx; nx < dex; nx++) {
r += *src++;
g += *src++;
b += *src++;
count++;
}
}
r /= count;
g /= count;
b /= count;
*dest++ = rgb_palette (r, g, b, snap->bgr);
}
}
free (snap);
return tex;
}
static int snap_pending;
static void
snap_capture (tex_t *snap, void *data)
{
int pcx_len;
pcx_t *pcx = 0;
tex_t *tex = cruch_snap (snap, RSSHOT_WIDTH, RSSHOT_HEIGHT);
snap_pending = 0;
if (tex) {
time_t now;
time (&now);
dstring_t *st = dstring_strdup (ctime (&now));
dstring_snip (st, strlen (st->str) - 1, 1);
snap_drawstring (st->str, tex, tex->width - strlen (st->str) * 8,
tex->height - 1);
dstring_copystr (st, cls.servername->str);
snap_drawstring (st->str, tex, tex->width - strlen (st->str) * 8,
tex->height - 11);
dstring_copystr (st, cl_name);
snap_drawstring (st->str, tex, tex->width - strlen (st->str) * 8,
tex->height - 21);
pcx = EncodePCX (tex->data, tex->width, tex->height, tex->width,
r_data->vid->basepal, tex->flipped, &pcx_len);
free (tex);
}
if (pcx) {
CL_StartUpload ((void *)pcx, pcx_len);
Sys_Printf ("Wrote %s\n", "rss.pcx");
Sys_Printf ("Sending shot to server...\n");
}
}
void
CL_RSShot_f (void)
{
if (snap_pending || CL_IsUploading ())
return; // already one pending
if (cls.state < ca_onserver)
return; // must be connected
Sys_Printf ("Remote screen shot requested.\n");
snap_pending = 1;
r_funcs->capture_screen (snap_capture, 0);
}