Remove all PTI code, use libpng to load avatars and thumbnails
Also write PNGs with libpng, and BMPs with SDL, and have the renderer only generate a large PNG thumbnail, and disable HTTP/2 multiplexing for now so we don't get banned when loading avatars. simon pls reply to the stupid emails already.
This commit is contained in:
parent
3cda085bac
commit
59354731df
@ -45,9 +45,9 @@ Libraries and other assets used
|
||||
* [FFTW](http://fftw.org/)
|
||||
* [JsonCpp](https://github.com/open-source-parsers/jsoncpp)
|
||||
* [libcurl](https://curl.se/libcurl/)
|
||||
* [libpng](http://www.libpng.org/pub/png/libpng.html)
|
||||
* [Lua](https://www.lua.org/)
|
||||
* [LuaJIT](https://luajit.org/)
|
||||
* [LuaSocket](http://w3.impa.br/~diego/software/luasocket/)
|
||||
* [Mallangche](https://github.com/JammPark/Mallangche)
|
||||
* [mbedtls](https://www.trustedfirmware.org/projects/mbed-tls/)
|
||||
* [SDL](https://libsdl.org/)
|
||||
|
4118
data/icon.cpp
4118
data/icon.cpp
File diff suppressed because it is too large
Load Diff
22
data/icon.h
22
data/icon.h
@ -1,22 +0,0 @@
|
||||
/**
|
||||
* Powder Toy - Main source
|
||||
*
|
||||
* Copyright (c) 2008 - 2010 Stanislaw Skowronek.
|
||||
* Copyright (c) 2010 Simon Robertshaw
|
||||
*
|
||||
* 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 the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
#pragma once
|
||||
extern const unsigned char app_icon[];
|
@ -1,6 +1,5 @@
|
||||
data_files += files(
|
||||
'hmap.cpp',
|
||||
'icon.cpp',
|
||||
'images.cpp',
|
||||
)
|
||||
data_files += to_array.process('font.bz2', extra_args: 'compressed_font_data')
|
||||
|
10
meson.build
10
meson.build
@ -171,6 +171,7 @@ fftw_dep = enable_gravfft ? dependency('fftw3f', static: is_static) : []
|
||||
|
||||
threads_dep = dependency('threads')
|
||||
zlib_dep = dependency('zlib', static: is_static)
|
||||
png_dep = dependency('libpng16', static: is_static)
|
||||
sdl2_dep = dependency('sdl2', static: is_static)
|
||||
bzip2_dep = dependency('bzip2', static: is_static)
|
||||
json_dep = dependency('jsoncpp', static: is_static)
|
||||
@ -349,6 +350,7 @@ if get_option('build_powder')
|
||||
powder_deps = [
|
||||
threads_dep,
|
||||
zlib_dep,
|
||||
png_dep,
|
||||
sdl2_dep,
|
||||
lua_dep,
|
||||
curl_dep,
|
||||
@ -387,14 +389,19 @@ if get_option('build_render')
|
||||
zlib_dep,
|
||||
bzip2_dep,
|
||||
json_dep,
|
||||
png_dep,
|
||||
]
|
||||
render_link_args = project_link_args
|
||||
if host_platform == 'linux' and is_static
|
||||
render_link_args += [ '-static' ]
|
||||
endif
|
||||
executable(
|
||||
'render',
|
||||
sources: render_files,
|
||||
include_directories: [ project_inc, render_inc ],
|
||||
c_args: project_c_args,
|
||||
cpp_args: project_cpp_args,
|
||||
link_args: project_link_args,
|
||||
link_args: render_link_args,
|
||||
dependencies: render_deps,
|
||||
)
|
||||
endif
|
||||
@ -403,6 +410,7 @@ if get_option('build_font')
|
||||
font_deps = [
|
||||
threads_dep,
|
||||
zlib_dep,
|
||||
png_dep,
|
||||
sdl2_dep,
|
||||
bzip2_dep,
|
||||
json_dep,
|
||||
|
@ -1,16 +0,0 @@
|
||||
import sys
|
||||
from PIL import Image
|
||||
image = Image.open(sys.argv[1])
|
||||
|
||||
output = ""
|
||||
formatted = []
|
||||
for pixel in image.getdata():
|
||||
formatted.extend("0x{0:02X}".format(byte) for byte in pixel)
|
||||
for i in range(len(formatted)/16 + 1):
|
||||
print(", ".join(formatted[i*16:(i+1)*16]) + ",")
|
||||
|
||||
"""with open(sys.argv[1], "rb") as icon:
|
||||
icondata = icon.read()
|
||||
output = ["0x{0:02X}".format(ord(byte)) for byte in icondata]
|
||||
for line in range(len(output)/16+1):
|
||||
print(", ".join(output[line*16:(line+1)*16])+",")"""
|
@ -9,18 +9,21 @@ if host_platform == 'windows'
|
||||
)
|
||||
endif
|
||||
|
||||
data_files += to_array.process('cps16.png', extra_args: 'cps16_png')
|
||||
data_files += to_array.process('cps32.png', extra_args: 'cps32_png')
|
||||
data_files += to_array.process('exe48.png', extra_args: 'exe48_png')
|
||||
data_files += to_array.process('save.xml', extra_args: 'save_xml')
|
||||
data_files += to_array.process(configure_file(
|
||||
input: 'powder.template.desktop',
|
||||
output: 'powder.desktop',
|
||||
configuration: conf_data,
|
||||
), extra_args: 'powder_desktop')
|
||||
if host_platform == 'linux'
|
||||
data_files += to_array.process('cps16.png', extra_args: 'cps16_png')
|
||||
data_files += to_array.process('cps32.png', extra_args: 'cps32_png')
|
||||
data_files += to_array.process('exe48.png', extra_args: 'exe48_png')
|
||||
data_files += to_array.process('icon/powder-128.png', extra_args: 'icon_png')
|
||||
data_files += to_array.process('save.xml', extra_args: 'save_xml')
|
||||
data_files += to_array.process(configure_file(
|
||||
input: 'powder.template.desktop',
|
||||
output: 'powder.desktop',
|
||||
configuration: conf_data,
|
||||
), extra_args: 'powder_desktop')
|
||||
|
||||
configure_file(
|
||||
input: 'appdata.template.xml',
|
||||
output: 'appdata.xml',
|
||||
configuration: conf_data,
|
||||
)
|
||||
configure_file(
|
||||
input: 'appdata.template.xml',
|
||||
output: 'appdata.xml',
|
||||
configuration: conf_data,
|
||||
)
|
||||
endif
|
||||
|
334
src/Format.cpp
334
src/Format.cpp
@ -10,6 +10,10 @@
|
||||
|
||||
#include "graphics/Graphics.h"
|
||||
|
||||
#ifndef RENDERER
|
||||
# include "SDLCompat.h"
|
||||
#endif
|
||||
|
||||
ByteString format::UnixtimeToDate(time_t unixtime, ByteString dateFormat)
|
||||
{
|
||||
struct tm * timeData;
|
||||
@ -95,77 +99,6 @@ String format::CleanString(String dirtyString, bool ascii, bool color, bool newl
|
||||
return dirtyString;
|
||||
}
|
||||
|
||||
std::vector<char> format::VideoBufferToPTI(const VideoBuffer & vidBuf)
|
||||
{
|
||||
std::vector<char> data;
|
||||
int dataSize = 0;
|
||||
char * buffer = (char*)Graphics::ptif_pack(vidBuf.Buffer, vidBuf.Width, vidBuf.Height, &dataSize);
|
||||
|
||||
if(buffer)
|
||||
{
|
||||
data.insert(data.end(), buffer, buffer+dataSize);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
VideoBuffer * format::PTIToVideoBuffer(std::vector<char> & data)
|
||||
{
|
||||
|
||||
int newWidth, newHeight;
|
||||
pixel * buffer = Graphics::ptif_unpack(&data[0], data.size(), &newWidth, &newHeight);
|
||||
|
||||
if(buffer)
|
||||
{
|
||||
VideoBuffer * vb = new VideoBuffer(buffer, newWidth, newHeight);
|
||||
free(buffer);
|
||||
return vb;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<char> format::VideoBufferToBMP(const VideoBuffer & vidBuf)
|
||||
{
|
||||
std::vector<char> data;
|
||||
char buffer[54] = "BM";
|
||||
int padding = 3 - (vidBuf.Width * 3 + 3) % 4;
|
||||
unsigned int fileSize = (vidBuf.Width * 3 + padding) * vidBuf.Height + 54;
|
||||
*(int *)(buffer + 2) = fileSize;
|
||||
*(short int *)(buffer + 6) = 0; // reserved;
|
||||
*(short int *)(buffer + 8) = 0; // reserved;
|
||||
*(int *)(buffer + 10) = 0x36; // 54 bytes from start to data
|
||||
*(int *)(buffer + 14) = 0x28; // 40 bytes in info header
|
||||
*(int *)(buffer + 18) = vidBuf.Width;
|
||||
*(int *)(buffer + 22) = vidBuf.Height;
|
||||
*(short int *)(buffer + 26) = 1; // 1 plane
|
||||
*(short int *)(buffer + 28) = 24; // 24 bits per pixel
|
||||
*(int *)(buffer + 30) = 0; // no compression
|
||||
*(int *)(buffer + 34) = fileSize - 54; // bitmap size
|
||||
*(int *)(buffer + 38) = 0xB13; // 72dpi
|
||||
*(int *)(buffer + 42) = 0xB13; // 72dpi
|
||||
*(int *)(buffer + 46) = 0; // all colors used
|
||||
*(int *)(buffer + 50) = 0; // all colors important
|
||||
|
||||
data.insert(data.end(), buffer, buffer+54);
|
||||
|
||||
char *currentRow = (char *)malloc((vidBuf.Width * 3) + padding);
|
||||
for(int y = vidBuf.Height - 1; y >= 0; y--)
|
||||
{
|
||||
int rowPos = 0;
|
||||
for(int x = 0; x < vidBuf.Width; x++)
|
||||
{
|
||||
currentRow[rowPos++] = PIXB(vidBuf.Buffer[(y*vidBuf.Width)+x]);
|
||||
currentRow[rowPos++] = PIXG(vidBuf.Buffer[(y*vidBuf.Width)+x]);
|
||||
currentRow[rowPos++] = PIXR(vidBuf.Buffer[(y*vidBuf.Width)+x]);
|
||||
}
|
||||
data.insert(data.end(), currentRow, currentRow+(vidBuf.Width*3)+padding);
|
||||
}
|
||||
free(currentRow);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<char> format::VideoBufferToPPM(const VideoBuffer & vidBuf)
|
||||
{
|
||||
std::vector<char> data;
|
||||
@ -190,264 +123,7 @@ std::vector<char> format::VideoBufferToPPM(const VideoBuffer & vidBuf)
|
||||
return data;
|
||||
}
|
||||
|
||||
struct PNGChunk
|
||||
{
|
||||
int Length;
|
||||
char Name[4];
|
||||
char * Data;
|
||||
|
||||
//char[4] CRC();
|
||||
|
||||
PNGChunk(int length, ByteString name)
|
||||
{
|
||||
if (name.length()!=4)
|
||||
throw std::runtime_error("Invalid chunk name");
|
||||
std::copy(name.begin(), name.begin()+4, Name);
|
||||
Length = length;
|
||||
if (length)
|
||||
{
|
||||
Data = new char[length];
|
||||
std::fill(Data, Data+length, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Data = NULL;
|
||||
}
|
||||
}
|
||||
unsigned long CRC()
|
||||
{
|
||||
if (!Data)
|
||||
{
|
||||
return format::CalculateCRC((unsigned char*)Name, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char * temp = new unsigned char[4+Length];
|
||||
std::copy(Name, Name+4, temp);
|
||||
std::copy(Data, Data+Length, temp+4);
|
||||
unsigned long tempRet = format::CalculateCRC(temp, 4+Length);
|
||||
delete[] temp;
|
||||
return tempRet;
|
||||
}
|
||||
}
|
||||
~PNGChunk()
|
||||
{
|
||||
delete[] Data;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<char> format::VideoBufferToPNG(const VideoBuffer & vidBuf)
|
||||
{
|
||||
std::vector<PNGChunk*> chunks;
|
||||
|
||||
//Begin IHDR (Image header) chunk (Image size and depth)
|
||||
PNGChunk *IHDRChunk = new PNGChunk(13, "IHDR");
|
||||
|
||||
//Image Width
|
||||
IHDRChunk->Data[0] = (vidBuf.Width>>24)&0xFF;
|
||||
IHDRChunk->Data[1] = (vidBuf.Width>>16)&0xFF;
|
||||
IHDRChunk->Data[2] = (vidBuf.Width>>8)&0xFF;
|
||||
IHDRChunk->Data[3] = (vidBuf.Width)&0xFF;
|
||||
|
||||
//Image Height
|
||||
IHDRChunk->Data[4] = (vidBuf.Height>>24)&0xFF;
|
||||
IHDRChunk->Data[5] = (vidBuf.Height>>16)&0xFF;
|
||||
IHDRChunk->Data[6] = (vidBuf.Height>>8)&0xFF;
|
||||
IHDRChunk->Data[7] = (vidBuf.Height)&0xFF;
|
||||
|
||||
//Bit depth
|
||||
IHDRChunk->Data[8] = 8; //8bits per channel or 24bpp
|
||||
|
||||
//Colour type
|
||||
IHDRChunk->Data[9] = 2; //RGB triple
|
||||
|
||||
//Everything else is default
|
||||
chunks.push_back(IHDRChunk);
|
||||
|
||||
//Begin image data, format is 8bit RGB (24bit pixel)
|
||||
int dataPos = 0;
|
||||
unsigned char * uncompressedData = new unsigned char[(vidBuf.Width*vidBuf.Height*3)+vidBuf.Height];
|
||||
|
||||
//Byte ordering and filtering
|
||||
unsigned char * previousRow = new unsigned char[vidBuf.Width*3];
|
||||
std::fill(previousRow, previousRow+(vidBuf.Width*3), 0);
|
||||
unsigned char * currentRow = new unsigned char[vidBuf.Width*3];
|
||||
for(int y = 0; y < vidBuf.Height; y++)
|
||||
{
|
||||
int rowPos = 0;
|
||||
for(int x = 0; x < vidBuf.Width; x++)
|
||||
{
|
||||
currentRow[rowPos++] = PIXR(vidBuf.Buffer[(y*vidBuf.Width)+x]);
|
||||
currentRow[rowPos++] = PIXG(vidBuf.Buffer[(y*vidBuf.Width)+x]);
|
||||
currentRow[rowPos++] = PIXB(vidBuf.Buffer[(y*vidBuf.Width)+x]);
|
||||
}
|
||||
|
||||
uncompressedData[dataPos++] = 2; //Up Sub(x) filter
|
||||
for(int b = 0; b < rowPos; b++)
|
||||
{
|
||||
int filteredByte = (currentRow[b]-previousRow[b])&0xFF;
|
||||
uncompressedData[dataPos++] = filteredByte;
|
||||
}
|
||||
|
||||
unsigned char * tempRow = previousRow;
|
||||
previousRow = currentRow;
|
||||
currentRow = tempRow;
|
||||
}
|
||||
delete[] currentRow;
|
||||
delete[] previousRow;
|
||||
|
||||
//Compression
|
||||
int compressedBufferSize = (vidBuf.Width*vidBuf.Height*3)*2;
|
||||
unsigned char * compressedData = new unsigned char[compressedBufferSize];
|
||||
|
||||
int result;
|
||||
z_stream zipStream;
|
||||
zipStream.zalloc = Z_NULL;
|
||||
zipStream.zfree = Z_NULL;
|
||||
zipStream.opaque = Z_NULL;
|
||||
|
||||
result = deflateInit2(&zipStream,
|
||||
9, // level
|
||||
Z_DEFLATED, // method
|
||||
10, // windowBits
|
||||
1, // memLevel
|
||||
Z_DEFAULT_STRATEGY // strategy
|
||||
);
|
||||
|
||||
if (result != Z_OK) exit(result);
|
||||
|
||||
zipStream.next_in = uncompressedData;
|
||||
zipStream.avail_in = dataPos;
|
||||
|
||||
zipStream.next_out = compressedData;
|
||||
zipStream.avail_out = compressedBufferSize;
|
||||
|
||||
|
||||
result = deflate(&zipStream, Z_FINISH);
|
||||
if (result != Z_STREAM_END) exit(result);
|
||||
|
||||
int compressedSize = compressedBufferSize-zipStream.avail_out;
|
||||
PNGChunk *IDATChunk = new PNGChunk(compressedSize, "IDAT");
|
||||
std::copy(compressedData, compressedData+compressedSize, IDATChunk->Data);
|
||||
chunks.push_back(IDATChunk);
|
||||
|
||||
deflateEnd(&zipStream);
|
||||
|
||||
delete[] compressedData;
|
||||
delete[] uncompressedData;
|
||||
|
||||
PNGChunk *IENDChunk = new PNGChunk(0, "IEND");
|
||||
chunks.push_back(IENDChunk);
|
||||
|
||||
//Write chunks to output buffer
|
||||
int finalDataSize = 8;
|
||||
for(std::vector<PNGChunk*>::iterator iter = chunks.begin(), end = chunks.end(); iter != end; ++iter)
|
||||
{
|
||||
PNGChunk * cChunk = *iter;
|
||||
finalDataSize += 4 + 4 + 4;
|
||||
finalDataSize += cChunk->Length;
|
||||
}
|
||||
unsigned char * finalData = new unsigned char[finalDataSize];
|
||||
int finalDataPos = 0;
|
||||
|
||||
//PNG File header
|
||||
finalData[finalDataPos++] = 0x89;
|
||||
finalData[finalDataPos++] = 0x50;
|
||||
finalData[finalDataPos++] = 0x4E;
|
||||
finalData[finalDataPos++] = 0x47;
|
||||
finalData[finalDataPos++] = 0x0D;
|
||||
finalData[finalDataPos++] = 0x0A;
|
||||
finalData[finalDataPos++] = 0x1A;
|
||||
finalData[finalDataPos++] = 0x0A;
|
||||
|
||||
for(std::vector<PNGChunk*>::iterator iter = chunks.begin(), end = chunks.end(); iter != end; ++iter)
|
||||
{
|
||||
PNGChunk * cChunk = *iter;
|
||||
|
||||
//Chunk length
|
||||
finalData[finalDataPos++] = (cChunk->Length>>24)&0xFF;
|
||||
finalData[finalDataPos++] = (cChunk->Length>>16)&0xFF;
|
||||
finalData[finalDataPos++] = (cChunk->Length>>8)&0xFF;
|
||||
finalData[finalDataPos++] = (cChunk->Length)&0xFF;
|
||||
|
||||
//Chunk name
|
||||
std::copy(cChunk->Name, cChunk->Name+4, finalData+finalDataPos);
|
||||
finalDataPos += 4;
|
||||
|
||||
//Chunk data
|
||||
if(cChunk->Data)
|
||||
{
|
||||
std::copy(cChunk->Data, cChunk->Data+cChunk->Length, finalData+finalDataPos);
|
||||
finalDataPos += cChunk->Length;
|
||||
}
|
||||
|
||||
//Chunk CRC
|
||||
unsigned long tempCRC = cChunk->CRC();
|
||||
finalData[finalDataPos++] = (tempCRC>>24)&0xFF;
|
||||
finalData[finalDataPos++] = (tempCRC>>16)&0xFF;
|
||||
finalData[finalDataPos++] = (tempCRC>>8)&0xFF;
|
||||
finalData[finalDataPos++] = (tempCRC)&0xFF;
|
||||
|
||||
delete cChunk;
|
||||
}
|
||||
|
||||
std::vector<char> outputData(finalData, finalData+finalDataPos);
|
||||
|
||||
delete[] finalData;
|
||||
|
||||
return outputData;
|
||||
}
|
||||
|
||||
//CRC functions, copypasta from W3 PNG spec.
|
||||
|
||||
/* Table of CRCs of all 8-bit messages. */
|
||||
unsigned long crc_table[256];
|
||||
|
||||
/* Flag: has the table been computed? Initially false. */
|
||||
int crc_table_computed = 0;
|
||||
|
||||
/* Make the table for a fast CRC. */
|
||||
void make_crc_table(void)
|
||||
{
|
||||
unsigned long c;
|
||||
int n, k;
|
||||
|
||||
for (n = 0; n < 256; n++) {
|
||||
c = (unsigned long) n;
|
||||
for (k = 0; k < 8; k++) {
|
||||
if (c & 1)
|
||||
c = 0xedb88320L ^ (c >> 1);
|
||||
else
|
||||
c = c >> 1;
|
||||
}
|
||||
crc_table[n] = c;
|
||||
}
|
||||
crc_table_computed = 1;
|
||||
}
|
||||
|
||||
/* Update a running CRC with the bytes buf[0..len-1]--the CRC
|
||||
should be initialized to all 1's, and the transmitted value
|
||||
is the 1's complement of the final running CRC (see the
|
||||
crc() routine below)). */
|
||||
|
||||
unsigned long update_crc(unsigned long crc, unsigned char *buf, int len)
|
||||
{
|
||||
unsigned long c = crc;
|
||||
int n;
|
||||
|
||||
if (!crc_table_computed)
|
||||
make_crc_table();
|
||||
for (n = 0; n < len; n++)
|
||||
{
|
||||
c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned long format::CalculateCRC(unsigned char * data, int len)
|
||||
{
|
||||
return update_crc(0xffffffffL, data, len) ^ 0xffffffffL;
|
||||
}
|
||||
const static char hex[] = "0123456789ABCDEF";
|
||||
|
||||
ByteString format::URLEncode(ByteString source)
|
||||
{
|
||||
|
@ -8,17 +8,10 @@ class VideoBuffer;
|
||||
|
||||
namespace format
|
||||
{
|
||||
const static char hex[] = "0123456789ABCDEF";
|
||||
|
||||
ByteString URLEncode(ByteString value);
|
||||
ByteString URLDecode(ByteString value);
|
||||
ByteString UnixtimeToDate(time_t unixtime, ByteString dateFomat = ByteString("%d %b %Y"));
|
||||
ByteString UnixtimeToDateMini(time_t unixtime);
|
||||
String CleanString(String dirtyString, bool ascii, bool color, bool newlines, bool numeric = false);
|
||||
std::vector<char> VideoBufferToPNG(const VideoBuffer & vidBuf);
|
||||
std::vector<char> VideoBufferToBMP(const VideoBuffer & vidBuf);
|
||||
std::vector<char> VideoBufferToPPM(const VideoBuffer & vidBuf);
|
||||
std::vector<char> VideoBufferToPTI(const VideoBuffer & vidBuf);
|
||||
VideoBuffer * PTIToVideoBuffer(std::vector<char> & data);
|
||||
unsigned long CalculateCRC(unsigned char * data, int length);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#if defined(LIN)
|
||||
#include "icon.h"
|
||||
# include "powder-128.png.h"
|
||||
#endif
|
||||
#include <stdexcept>
|
||||
|
||||
@ -157,9 +157,14 @@ int SDLOpen()
|
||||
SendMessage(WindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hIconBig);
|
||||
#endif
|
||||
#ifdef LIN
|
||||
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom((void*)app_icon, 128, 128, 32, 512, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
|
||||
SDL_SetWindowIcon(sdl_window, icon);
|
||||
SDL_FreeSurface(icon);
|
||||
std::vector<pixel> imageData;
|
||||
int imgw, imgh;
|
||||
if (PngDataToPixels(imageData, imgw, imgh, reinterpret_cast<const char *>(icon_png), icon_png_size, false))
|
||||
{
|
||||
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(&imageData[0], imgw, imgh, 32, imgw * sizeof(pixel), 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
|
||||
SDL_SetWindowIcon(sdl_window, icon);
|
||||
SDL_FreeSurface(icon);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@ -289,11 +294,11 @@ void EventProcess(SDL_Event event)
|
||||
break;
|
||||
case SDL_MOUSEWHEEL:
|
||||
{
|
||||
int x = event.wheel.x;
|
||||
// int x = event.wheel.x;
|
||||
int y = event.wheel.y;
|
||||
if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
|
||||
{
|
||||
x *= -1;
|
||||
// x *= -1;
|
||||
y *= -1;
|
||||
}
|
||||
|
||||
|
@ -22,64 +22,40 @@ int GetModifiers() { return 0; }
|
||||
void SetCursorEnabled(int enabled) {}
|
||||
unsigned int GetTicks() { return 0; }
|
||||
|
||||
void readFile(ByteString filename, std::vector<char> & storage)
|
||||
static bool ReadFile(std::vector<char> &fileData, ByteString filename)
|
||||
{
|
||||
std::ifstream fileStream;
|
||||
fileStream.open(filename.c_str(), std::ios::binary);
|
||||
if(fileStream.is_open())
|
||||
std::ifstream f(filename, std::ios::binary);
|
||||
if (f) f.seekg(0, std::ios::end);
|
||||
if (f) fileData.resize(f.tellg());
|
||||
if (f) f.seekg(0);
|
||||
if (f) f.read(&fileData[0], fileData.size());
|
||||
if (!f)
|
||||
{
|
||||
fileStream.seekg(0, std::ios::end);
|
||||
size_t fileSize = fileStream.tellg();
|
||||
fileStream.seekg(0);
|
||||
|
||||
unsigned char * tempData = new unsigned char[fileSize];
|
||||
fileStream.read((char *)tempData, fileSize);
|
||||
fileStream.close();
|
||||
|
||||
std::vector<unsigned char> fileData;
|
||||
storage.clear();
|
||||
storage.insert(storage.end(), tempData, tempData+fileSize);
|
||||
delete[] tempData;
|
||||
}
|
||||
}
|
||||
|
||||
void writeFile(ByteString filename, std::vector<char> & fileData)
|
||||
{
|
||||
std::ofstream fileStream;
|
||||
fileStream.open(filename.c_str(), std::ios::binary);
|
||||
if(fileStream.is_open())
|
||||
{
|
||||
fileStream.write(&fileData[0], fileData.size());
|
||||
fileStream.close();
|
||||
std::cerr << "ReadFile: " << filename << ": " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
ByteString outputPrefix, inputFilename;
|
||||
std::vector<char> inputFile;
|
||||
ByteString ppmFilename, ptiFilename, ptiSmallFilename, pngFilename, pngSmallFilename;
|
||||
std::vector<char> ppmFile, ptiFile, ptiSmallFile, pngFile, pngSmallFile;
|
||||
|
||||
if (!argv[1] || !argv[2]) {
|
||||
std::cout << "Usage: " << argv[0] << " <inputFilename> <outputPrefix>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
inputFilename = argv[1];
|
||||
outputPrefix = argv[2];
|
||||
auto inputFilename = ByteString(argv[1]);
|
||||
auto outputFilename = ByteString(argv[2]) + ".png";
|
||||
|
||||
ppmFilename = outputPrefix+".ppm";
|
||||
ptiFilename = outputPrefix+".pti";
|
||||
ptiSmallFilename = outputPrefix+"-small.pti";
|
||||
pngFilename = outputPrefix+".png";
|
||||
pngSmallFilename = outputPrefix+"-small.png";
|
||||
|
||||
readFile(inputFilename, inputFile);
|
||||
std::vector<char> fileData;
|
||||
if (!ReadFile(fileData, inputFilename))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
GameSave * gameSave = NULL;
|
||||
try
|
||||
{
|
||||
gameSave = new GameSave(inputFile);
|
||||
gameSave = new GameSave(fileData);
|
||||
}
|
||||
catch (ParseException &e)
|
||||
{
|
||||
@ -119,19 +95,5 @@ int main(int argc, char *argv[])
|
||||
ren->RenderEnd();
|
||||
|
||||
VideoBuffer screenBuffer = ren->DumpFrame();
|
||||
//ppmFile = format::VideoBufferToPPM(screenBuffer);
|
||||
ptiFile = format::VideoBufferToPTI(screenBuffer);
|
||||
pngFile = format::VideoBufferToPNG(screenBuffer);
|
||||
|
||||
screenBuffer.Resize(1.0f/3.0f, true);
|
||||
ptiSmallFile = format::VideoBufferToPTI(screenBuffer);
|
||||
pngSmallFile = format::VideoBufferToPNG(screenBuffer);
|
||||
|
||||
|
||||
|
||||
//writeFile(ppmFilename, ppmFile);
|
||||
writeFile(ptiFilename, ptiFile);
|
||||
writeFile(ptiSmallFilename, ptiSmallFile);
|
||||
writeFile(pngFilename, pngFile);
|
||||
writeFile(pngSmallFilename, pngSmallFile);
|
||||
screenBuffer.WritePNG(outputFilename);
|
||||
}
|
||||
|
@ -17,9 +17,8 @@
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include "Config.h"
|
||||
#if defined(LIN)
|
||||
#include "icon.h"
|
||||
# include "powder-128.png.h"
|
||||
#endif
|
||||
#include <csignal>
|
||||
#include <stdexcept>
|
||||
@ -214,9 +213,14 @@ void SDLOpen()
|
||||
SendMessage(WindowHandle, WM_SETICON, ICON_BIG, (LPARAM)hIconBig);
|
||||
#endif
|
||||
#ifdef LIN
|
||||
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom((void*)app_icon, 128, 128, 32, 512, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
|
||||
SDL_SetWindowIcon(sdl_window, icon);
|
||||
SDL_FreeSurface(icon);
|
||||
std::vector<pixel> imageData;
|
||||
int imgw, imgh;
|
||||
if (PngDataToPixels(imageData, imgw, imgh, reinterpret_cast<const char *>(icon_png), icon_png_size, false))
|
||||
{
|
||||
SDL_Surface *icon = SDL_CreateRGBSurfaceFrom(&imageData[0], imgw, imgh, 32, imgw * sizeof(pixel), 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000);
|
||||
SDL_SetWindowIcon(sdl_window, icon);
|
||||
SDL_FreeSurface(icon);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1,16 +0,0 @@
|
||||
#include "AvatarRequest.h"
|
||||
|
||||
#include "Config.h"
|
||||
|
||||
namespace http
|
||||
{
|
||||
AvatarRequest::AvatarRequest(ByteString username, int width, int height) :
|
||||
ImageRequest(ByteString::Build(STATICSCHEME STATICSERVER "/avatars/", username, ".pti"), width, height)
|
||||
{
|
||||
}
|
||||
|
||||
AvatarRequest::~AvatarRequest()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +0,0 @@
|
||||
#ifndef AVATARREQUEST2_H
|
||||
#define AVATARREQUEST2_H
|
||||
|
||||
#include "ImageRequest.h"
|
||||
|
||||
namespace http
|
||||
{
|
||||
class AvatarRequest : public ImageRequest
|
||||
{
|
||||
public:
|
||||
AvatarRequest(ByteString username, int width, int height);
|
||||
virtual ~AvatarRequest();
|
||||
};
|
||||
}
|
||||
|
||||
#endif // AVATARREQUEST2_H
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "graphics/Graphics.h"
|
||||
#include "Config.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace http
|
||||
{
|
||||
ImageRequest::ImageRequest(ByteString url, int width, int height) :
|
||||
@ -29,11 +31,10 @@ namespace http
|
||||
if (data.size())
|
||||
{
|
||||
int imgw, imgh;
|
||||
pixel *imageData = Graphics::ptif_unpack(&data[0], data.size(), &imgw, &imgh);
|
||||
if (imageData)
|
||||
std::vector<pixel> imageData;
|
||||
if (PngDataToPixels(imageData, imgw, imgh, data.data(), data.size(), true))
|
||||
{
|
||||
vb = std::unique_ptr<VideoBuffer>(new VideoBuffer(imageData, imgw, imgh));
|
||||
free(imageData);
|
||||
vb = std::unique_ptr<VideoBuffer>(new VideoBuffer(imageData.data(), imgw, imgh));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5,7 +5,8 @@
|
||||
#include <iostream>
|
||||
|
||||
const int curl_multi_wait_timeout_ms = 100;
|
||||
const long curl_max_host_connections = 6;
|
||||
const long curl_max_host_connections = 1;
|
||||
const long curl_max_concurrent_streams = 1;
|
||||
|
||||
namespace http
|
||||
{
|
||||
@ -42,6 +43,9 @@ namespace http
|
||||
if (multi)
|
||||
{
|
||||
curl_multi_setopt(multi, CURLMOPT_MAX_HOST_CONNECTIONS, curl_max_host_connections);
|
||||
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 67, 0)
|
||||
curl_multi_setopt(multi, CURLMOPT_MAX_CONCURRENT_STREAMS, curl_max_concurrent_streams);
|
||||
#endif
|
||||
}
|
||||
|
||||
proxy = newProxy;
|
||||
|
@ -7,8 +7,8 @@ namespace http
|
||||
ThumbnailRequest::ThumbnailRequest(int saveID, int saveDate, int width, int height) :
|
||||
ImageRequest((
|
||||
saveDate
|
||||
? ByteString::Build(STATICSCHEME STATICSERVER "/", saveID, "_", saveDate, "_small.pti")
|
||||
: ByteString::Build(STATICSCHEME STATICSERVER "/", saveID, "_small.pti")
|
||||
? ByteString::Build(STATICSCHEME STATICSERVER "/", saveID, "_", saveDate, "_small.png")
|
||||
: ByteString::Build(STATICSCHEME STATICSERVER "/", saveID, "_small.png")
|
||||
), width, height)
|
||||
{
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
client_files += files(
|
||||
'APIRequest.cpp',
|
||||
'AvatarRequest.cpp',
|
||||
'GetUserInfoRequest.cpp',
|
||||
'ImageRequest.cpp',
|
||||
'Request.cpp',
|
||||
|
@ -6,12 +6,15 @@
|
||||
#include <cstring>
|
||||
|
||||
#include <bzlib.h>
|
||||
#include "common/Platform.h"
|
||||
|
||||
#include "FontReader.h"
|
||||
#ifdef HIGH_QUALITY_RESAMPLE
|
||||
#include "resampler/resampler.h"
|
||||
#endif
|
||||
|
||||
#include <png.h>
|
||||
|
||||
VideoBuffer::VideoBuffer(int width, int height):
|
||||
Width(width),
|
||||
Height(height)
|
||||
@ -186,115 +189,6 @@ char * Graphics::GenerateGradient(pixel * colours, float * points, int pointcoun
|
||||
return newdata;
|
||||
}
|
||||
|
||||
void *Graphics::ptif_pack(pixel *src, int w, int h, int *result_size){
|
||||
int i = 0, datalen = (w*h)*3, cx = 0, cy = 0;
|
||||
unsigned char *red_chan = (unsigned char*)calloc(1, w*h);
|
||||
unsigned char *green_chan = (unsigned char*)calloc(1, w*h);
|
||||
unsigned char *blue_chan = (unsigned char*)calloc(1, w*h);
|
||||
unsigned char *data = (unsigned char*)malloc(((w*h)*3)+8);
|
||||
unsigned char *result = (unsigned char*)malloc(((w*h)*3)+8);
|
||||
|
||||
for(cx = 0; cx<w; cx++){
|
||||
for(cy = 0; cy<h; cy++){
|
||||
red_chan[w*(cy)+(cx)] = PIXR(src[w*(cy)+(cx)]);
|
||||
green_chan[w*(cy)+(cx)] = PIXG(src[w*(cy)+(cx)]);
|
||||
blue_chan[w*(cy)+(cx)] = PIXB(src[w*(cy)+(cx)]);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(data, red_chan, w*h);
|
||||
memcpy(data+(w*h), green_chan, w*h);
|
||||
memcpy(data+((w*h)*2), blue_chan, w*h);
|
||||
free(red_chan);
|
||||
free(green_chan);
|
||||
free(blue_chan);
|
||||
|
||||
result[0] = 'P';
|
||||
result[1] = 'T';
|
||||
result[2] = 'i';
|
||||
result[3] = 1;
|
||||
result[4] = w;
|
||||
result[5] = w>>8;
|
||||
result[6] = h;
|
||||
result[7] = h>>8;
|
||||
|
||||
i -= 8;
|
||||
|
||||
if(BZ2_bzBuffToBuffCompress((char *)(result+8), (unsigned *)&i, (char *)data, datalen, 9, 0, 0) != 0){
|
||||
free(data);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*result_size = i+8;
|
||||
free(data);
|
||||
return result;
|
||||
}
|
||||
|
||||
pixel *Graphics::ptif_unpack(void *datain, int size, int *w, int *h){
|
||||
int width, height, i, cx, cy, resCode;
|
||||
unsigned char *red_chan;
|
||||
unsigned char *green_chan;
|
||||
unsigned char *blue_chan;
|
||||
unsigned char *data = (unsigned char*)datain;
|
||||
unsigned char *undata;
|
||||
pixel *result;
|
||||
if(size<16){
|
||||
printf("Image empty\n");
|
||||
return NULL;
|
||||
}
|
||||
if(!(data[0]=='P' && data[1]=='T' && data[2]=='i')){
|
||||
printf("Image header invalid\n");
|
||||
return NULL;
|
||||
}
|
||||
width = data[4]|(data[5]<<8);
|
||||
height = data[6]|(data[7]<<8);
|
||||
|
||||
i = (width*height)*3;
|
||||
undata = (unsigned char*)calloc(1, (width*height)*3);
|
||||
red_chan = (unsigned char*)calloc(1, width*height);
|
||||
green_chan = (unsigned char*)calloc(1, width*height);
|
||||
blue_chan = (unsigned char *)calloc(1, width*height);
|
||||
result = (pixel *)calloc(width*height, PIXELSIZE);
|
||||
|
||||
resCode = BZ2_bzBuffToBuffDecompress((char *)undata, (unsigned *)&i, (char *)(data+8), size-8, 0, 0);
|
||||
if (resCode){
|
||||
printf("Decompression failure, %d\n", resCode);
|
||||
free(red_chan);
|
||||
free(green_chan);
|
||||
free(blue_chan);
|
||||
free(undata);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
if(i != (width*height)*3){
|
||||
printf("Result buffer size mismatch, %d != %d\n", i, (width*height)*3);
|
||||
free(red_chan);
|
||||
free(green_chan);
|
||||
free(blue_chan);
|
||||
free(undata);
|
||||
free(result);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(red_chan, undata, width*height);
|
||||
memcpy(green_chan, undata+(width*height), width*height);
|
||||
memcpy(blue_chan, undata+((width*height)*2), width*height);
|
||||
|
||||
for(cx = 0; cx<width; cx++){
|
||||
for(cy = 0; cy<height; cy++){
|
||||
result[width*(cy)+(cx)] = PIXRGB(red_chan[width*(cy)+(cx)], green_chan[width*(cy)+(cx)], blue_chan[width*(cy)+(cx)]);
|
||||
}
|
||||
}
|
||||
|
||||
*w = width;
|
||||
*h = height;
|
||||
free(red_chan);
|
||||
free(green_chan);
|
||||
free(blue_chan);
|
||||
free(undata);
|
||||
return result;
|
||||
}
|
||||
|
||||
pixel *Graphics::resample_img_nn(pixel * src, int sw, int sh, int rw, int rh)
|
||||
{
|
||||
int y, x;
|
||||
@ -1101,3 +995,151 @@ void Graphics::SetClipRect(int &x, int &y, int &w, int &h)
|
||||
clipx2 = newX + newW;
|
||||
clipy2 = newY + newH;
|
||||
}
|
||||
|
||||
bool VideoBuffer::WritePNG(const ByteString &path) const
|
||||
{
|
||||
std::vector<png_const_bytep> rowPointers(Height);
|
||||
for (auto y = 0; y < Height; ++y)
|
||||
{
|
||||
rowPointers[y] = (png_const_bytep)&Buffer[y * Width];
|
||||
}
|
||||
#ifdef WIN
|
||||
FILE *f = _wfopen(Platform::WinWiden(path).c_str(), L"wb");
|
||||
#else
|
||||
FILE *f = fopen(path.c_str(), "wb");
|
||||
#endif
|
||||
if (!f)
|
||||
{
|
||||
std::cerr << "WritePNG: fopen failed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png)
|
||||
{
|
||||
std::cerr << "WritePNG: png_create_write_struct failed" << std::endl;
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if (!info)
|
||||
{
|
||||
std::cerr << "WritePNG: png_create_info_struct failed" << std::endl;
|
||||
png_destroy_write_struct(&png, (png_infopp)NULL);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
if (setjmp(png_jmpbuf(png)))
|
||||
{
|
||||
// libpng longjmp'd here in its infinite widsom, clean up and return
|
||||
std::cerr << "WritePNG: longjmp from within libpng" << std::endl;
|
||||
png_destroy_write_struct(&png, &info);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
png_init_io(png, f);
|
||||
png_set_IHDR(png, info, Width, Height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png, info);
|
||||
png_set_filler(png, 0, PNG_FILLER_AFTER);
|
||||
png_set_bgr(png);
|
||||
png_write_image(png, (png_bytepp)&rowPointers[0]);
|
||||
png_write_end(png, NULL);
|
||||
png_destroy_write_struct(&png, &info);
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PngDataToPixels(std::vector<pixel> &imageData, int &imgw, int &imgh, const char *pngData, size_t pngDataSize, bool addBackground)
|
||||
{
|
||||
std::vector<png_const_bytep> rowPointers;
|
||||
struct InMemoryFile
|
||||
{
|
||||
png_const_bytep data;
|
||||
size_t size;
|
||||
size_t cursor;
|
||||
} imf{ (png_const_bytep)pngData, pngDataSize, 0 };
|
||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png)
|
||||
{
|
||||
std::cerr << "pngDataToPixels: png_create_read_struct failed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
png_infop info = png_create_info_struct(png);
|
||||
if (!info)
|
||||
{
|
||||
std::cerr << "pngDataToPixels: png_create_info_struct failed" << std::endl;
|
||||
png_destroy_read_struct(&png, (png_infopp)NULL, (png_infopp)NULL);
|
||||
return false;
|
||||
}
|
||||
if (setjmp(png_jmpbuf(png)))
|
||||
{
|
||||
// libpng longjmp'd here in its infinite widsom, clean up and return
|
||||
std::cerr << "pngDataToPixels: longjmp from within libpng" << std::endl;
|
||||
png_destroy_read_struct(&png, &info, (png_infopp)NULL);
|
||||
return false;
|
||||
}
|
||||
png_set_read_fn(png, (png_voidp)&imf, [](png_structp png, png_bytep data, size_t length) -> void {
|
||||
auto ud = png_get_io_ptr(png);
|
||||
auto &imf = *(InMemoryFile *)ud;
|
||||
if (length + imf.cursor > imf.size)
|
||||
{
|
||||
png_error(png, "pngDataToPixels: libpng tried to read beyond the buffer");
|
||||
}
|
||||
std::copy(imf.data + imf.cursor, imf.data + imf.cursor + length, data);
|
||||
imf.cursor += length;
|
||||
});
|
||||
png_set_user_limits(png, 1000, 1000);
|
||||
png_read_info(png, info);
|
||||
imgw = png_get_image_width(png, info);
|
||||
imgh = png_get_image_height(png, info);
|
||||
int bitDepth = png_get_bit_depth(png, info);
|
||||
int colorType = png_get_color_type(png, info);
|
||||
imageData.resize(imgw * imgh);
|
||||
rowPointers.resize(imgh);
|
||||
for (auto y = 0; y < imgh; ++y)
|
||||
{
|
||||
rowPointers[y] = (png_const_bytep)&imageData[y * imgw];
|
||||
}
|
||||
if (setjmp(png_jmpbuf(png)))
|
||||
{
|
||||
// libpng longjmp'd here in its infinite widsom, clean up and return
|
||||
std::cerr << "pngDataToPixels: longjmp from within libpng" << std::endl;
|
||||
png_destroy_read_struct(&png, &info, (png_infopp)NULL);
|
||||
return false;
|
||||
}
|
||||
if (addBackground)
|
||||
{
|
||||
png_set_filler(png, 0, PNG_FILLER_AFTER);
|
||||
}
|
||||
png_set_bgr(png);
|
||||
if (colorType == PNG_COLOR_TYPE_PALETTE)
|
||||
{
|
||||
png_set_palette_to_rgb(png);
|
||||
}
|
||||
if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
|
||||
{
|
||||
png_set_expand_gray_1_2_4_to_8(png);
|
||||
}
|
||||
if (png_get_valid(png, info, PNG_INFO_tRNS))
|
||||
{
|
||||
png_set_tRNS_to_alpha(png);
|
||||
}
|
||||
if (bitDepth == 16)
|
||||
{
|
||||
png_set_scale_16(png);
|
||||
}
|
||||
if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||
{
|
||||
png_set_gray_to_rgb(png);
|
||||
}
|
||||
if (addBackground)
|
||||
{
|
||||
png_color_16 defaultBackground;
|
||||
defaultBackground.red = 0;
|
||||
defaultBackground.green = 0;
|
||||
defaultBackground.blue = 0;
|
||||
png_set_background(png, &defaultBackground, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
|
||||
}
|
||||
png_read_image(png, (png_bytepp)&rowPointers[0]);
|
||||
png_destroy_read_struct(&png, &info, (png_infopp)NULL);
|
||||
return true;
|
||||
}
|
||||
|
@ -66,6 +66,7 @@ public:
|
||||
~VideoBuffer();
|
||||
|
||||
void CopyData(pixel * buffer, int width, int height, int pitch);
|
||||
bool WritePNG(const ByteString &path) const;
|
||||
};
|
||||
|
||||
class Graphics
|
||||
@ -83,8 +84,6 @@ public:
|
||||
static char * GenerateGradient(pixel * colours, float * points, int pointcount, int size);
|
||||
|
||||
//PTIF methods
|
||||
static void *ptif_pack(pixel *src, int w, int h, int *result_size);
|
||||
static pixel *ptif_unpack(void *datain, int size, int *w, int *h);
|
||||
static pixel *resample_img_nn(pixel *src, int sw, int sh, int rw, int rh);
|
||||
static pixel *resample_img(pixel *src, int sw, int sh, int rw, int rh);
|
||||
static pixel *rescale_img(pixel *src, int sw, int sh, int *qw, int *qh, int f);
|
||||
@ -137,4 +136,6 @@ public:
|
||||
void SetClipRect(int &x, int &y, int &w, int &h);
|
||||
};
|
||||
|
||||
bool PngDataToPixels(std::vector<pixel> &imageData, int &imgw, int &imgh, const char *pngData, size_t pngDataSize, bool addBackground);
|
||||
|
||||
#endif
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "gui/interface/Engine.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef GetUserName
|
||||
# undef GetUserName // dammit windows
|
||||
@ -898,50 +899,68 @@ void GameView::NotifyBrushChanged(GameModel * sender)
|
||||
|
||||
ByteString GameView::TakeScreenshot(int captureUI, int fileType)
|
||||
{
|
||||
VideoBuffer *screenshot;
|
||||
std::vector<char> data;
|
||||
time_t screenshotTime = time(nullptr);
|
||||
std::string extension;
|
||||
|
||||
std::unique_ptr<VideoBuffer> screenshot;
|
||||
if (captureUI)
|
||||
screenshot = new VideoBuffer(ren->DumpFrame());
|
||||
{
|
||||
screenshot = std::make_unique<VideoBuffer>(ren->DumpFrame());
|
||||
}
|
||||
else
|
||||
screenshot = new VideoBuffer(ui::Engine::Ref().g->DumpFrame());
|
||||
{
|
||||
screenshot = std::make_unique<VideoBuffer>(ui::Engine::Ref().g->DumpFrame());
|
||||
}
|
||||
|
||||
ByteString filename;
|
||||
{
|
||||
// Optional suffix to distinguish screenshots taken at the exact same time
|
||||
ByteString suffix = "";
|
||||
time_t screenshotTime = time(nullptr);
|
||||
if (screenshotTime == lastScreenshotTime)
|
||||
{
|
||||
screenshotIndex++;
|
||||
suffix = ByteString::Build(" (", screenshotIndex, ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
screenshotIndex = 1;
|
||||
}
|
||||
lastScreenshotTime = screenshotTime;
|
||||
std::string date = format::UnixtimeToDate(screenshotTime, "%Y-%m-%d %H.%M.%S");
|
||||
filename = ByteString::Build("screenshot ", date, suffix);
|
||||
}
|
||||
|
||||
if (fileType == 1)
|
||||
{
|
||||
data = format::VideoBufferToBMP(screenshot);
|
||||
extension = ".bmp";
|
||||
filename += ".bmp";
|
||||
// We should be able to simply use SDL_PIXELFORMAT_XRGB8888 here with a bit depth of 32 to convert RGBA data to RGB data,
|
||||
// and save the resulting surface directly. However, ubuntu-18.04 ships SDL2 so old that it doesn't have
|
||||
// SDL_PIXELFORMAT_XRGB8888, so we first create an RGBA surface and then convert it.
|
||||
auto *rgbaSurface = SDL_CreateRGBSurfaceWithFormatFrom(screenshot->Buffer, screenshot->Width, screenshot->Height, 32, screenshot->Width * sizeof(pixel), SDL_PIXELFORMAT_ARGB8888);
|
||||
auto *rgbSurface = SDL_ConvertSurfaceFormat(rgbaSurface, SDL_PIXELFORMAT_RGB888, 0);
|
||||
if (!rgbSurface || SDL_SaveBMP(rgbSurface, filename.c_str()))
|
||||
{
|
||||
std::cerr << "SDL_SaveBMP failed: " << SDL_GetError() << std::endl;
|
||||
filename = "";
|
||||
}
|
||||
SDL_FreeSurface(rgbSurface);
|
||||
SDL_FreeSurface(rgbaSurface);
|
||||
}
|
||||
else if (fileType == 2)
|
||||
{
|
||||
data = format::VideoBufferToPPM(screenshot);
|
||||
extension = ".ppm";
|
||||
filename += ".ppm";
|
||||
if (!Platform::WriteFile(format::VideoBufferToPPM(*screenshot), filename))
|
||||
{
|
||||
filename = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
data = format::VideoBufferToPNG(screenshot);
|
||||
extension = ".png";
|
||||
filename += ".png";
|
||||
if (!screenshot->WritePNG(filename))
|
||||
{
|
||||
filename = "";
|
||||
}
|
||||
}
|
||||
|
||||
// Optional suffix to distinguish screenshots taken at the exact same time
|
||||
ByteString suffix = "";
|
||||
if (screenshotTime == lastScreenshotTime)
|
||||
{
|
||||
screenshotIndex++;
|
||||
suffix = ByteString::Build(" (", screenshotIndex, ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
screenshotIndex = 1;
|
||||
}
|
||||
std::string date = format::UnixtimeToDate(screenshotTime, "%Y-%m-%d %H.%M.%S");
|
||||
ByteString filename = ByteString::Build("screenshot ", date, suffix, extension);
|
||||
|
||||
Platform::WriteFile(data, filename);
|
||||
doScreenshot = false;
|
||||
lastScreenshotTime = screenshotTime;
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
@ -2155,6 +2174,7 @@ void GameView::OnDraw()
|
||||
|
||||
if (doScreenshot)
|
||||
{
|
||||
doScreenshot = false;
|
||||
TakeScreenshot(0, 0);
|
||||
}
|
||||
|
||||
|
@ -26,10 +26,12 @@ void AvatarButton::OnResponse(std::unique_ptr<VideoBuffer> Avatar)
|
||||
|
||||
void AvatarButton::Tick(float dt)
|
||||
{
|
||||
if(!avatar && !tried && name.size() > 0)
|
||||
if(!avatar && !tried)
|
||||
{
|
||||
tried = true;
|
||||
RequestSetup(name, Size.X, Size.Y);
|
||||
// TODO: Currently a very expensive-to-call endpoint; skips the cache server. If we call it too quickly, we get banned as
|
||||
// an anti-DoS measure. This is why concurrent connections / connection multiplexing have been temporarily disabled.
|
||||
RequestSetup(SCHEME SERVER "/Mini/GetAvatarPng.php?Username=" + name, Size.X, Size.Y);
|
||||
RequestStart();
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "Component.h"
|
||||
#include "graphics/Graphics.h"
|
||||
#include "gui/interface/Colour.h"
|
||||
#include "client/http/AvatarRequest.h"
|
||||
#include "client/http/ImageRequest.h"
|
||||
#include "client/http/RequestMonitor.h"
|
||||
|
||||
#include <memory>
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class AvatarButton : public Component, public http::RequestMonitor<http::AvatarRequest>
|
||||
class AvatarButton : public Component, public http::RequestMonitor<http::ImageRequest>
|
||||
{
|
||||
std::unique_ptr<VideoBuffer> avatar;
|
||||
ByteString name;
|
||||
|
@ -207,7 +207,7 @@ bool PreviewModel::ParseSaveInfo(ByteString &saveInfoResponse)
|
||||
{
|
||||
delete saveInfo;
|
||||
|
||||
try
|
||||
try // how does this differ from Client::GetSave?
|
||||
{
|
||||
std::istringstream dataStream(saveInfoResponse);
|
||||
Json::Value objDocument;
|
||||
|
@ -1323,8 +1323,12 @@ int luatpt_screenshot(lua_State* l)
|
||||
int fileType = luaL_optint(l, 2, 0);
|
||||
|
||||
ByteString filename = luacon_controller->TakeScreenshot(captureUI, fileType);
|
||||
tpt_lua_pushByteString(l, filename);
|
||||
return 1;
|
||||
if (filename.size())
|
||||
{
|
||||
tpt_lua_pushByteString(l, filename);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luatpt_record(lua_State* l)
|
||||
|
Loading…
Reference in New Issue
Block a user