Implement some missing lua functions, PNG format creation (requires zlib)
This commit is contained in:
parent
ecbb1e9103
commit
08b4e5553a
@ -97,6 +97,11 @@ if not conf.CheckLib('bz2'):
|
||||
print "libbz2 not found or not installed"
|
||||
raise SystemExit(1)
|
||||
|
||||
#Check for zlib
|
||||
if not conf.CheckLib('z'):
|
||||
print "libz not found or not installed"
|
||||
raise SystemExit(1)
|
||||
|
||||
if not conf.CheckCHeader("bzlib.h"):
|
||||
print "bzip2 headers not found"
|
||||
raise SystemExit(1)
|
||||
|
263
src/Format.cpp
263
src/Format.cpp
@ -1,7 +1,10 @@
|
||||
|
||||
#include <time.h>
|
||||
#include <ctime>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <zlib.h>
|
||||
#include "Format.h"
|
||||
#include "graphics/Graphics.h"
|
||||
|
||||
std::string format::UnixtimeToDate(time_t unixtime, std::string dateFormat)
|
||||
{
|
||||
@ -33,3 +36,261 @@ std::string format::UnixtimeToDateMini(time_t unixtime)
|
||||
return UnixtimeToDate(unixtime, "%H:%M:%S");
|
||||
}
|
||||
}
|
||||
|
||||
struct PNGChunk
|
||||
{
|
||||
int Length;
|
||||
char Name[4];
|
||||
char * Data;
|
||||
|
||||
//char[4] CRC();
|
||||
|
||||
PNGChunk(int length, std::string 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()
|
||||
{
|
||||
if(Data)
|
||||
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 = 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 = PNGChunk(compressedSize, "IDAT");
|
||||
std::copy(compressedData, compressedData+compressedSize, IDATChunk.Data);
|
||||
chunks.push_back(&IDATChunk);
|
||||
|
||||
deflateEnd(&zipStream);
|
||||
|
||||
delete[] compressedData;
|
||||
delete[] uncompressedData;
|
||||
|
||||
PNGChunk IENDChunk = 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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
class VideoBuffer;
|
||||
namespace format
|
||||
{
|
||||
template <typename T> std::string NumberToString(T number)
|
||||
@ -20,4 +22,6 @@ namespace format
|
||||
|
||||
std::string UnixtimeToDate(time_t unixtime, std::string dateFomat = "%d %b %Y");
|
||||
std::string UnixtimeToDateMini(time_t unixtime);
|
||||
std::vector<char> VideoBufferToPNG(const VideoBuffer & vidBuf);
|
||||
unsigned long CalculateCRC(unsigned char * data, int length);
|
||||
}
|
@ -7,8 +7,11 @@
|
||||
|
||||
#include <string>
|
||||
#include "Config.h"
|
||||
#include "Format.h"
|
||||
#include "LuaScriptInterface.h"
|
||||
#include "TPTScriptInterface.h"
|
||||
#include "dialogues/ErrorMessage.h"
|
||||
#include "dialogues/InformationMessage.h"
|
||||
#include "simulation/Simulation.h"
|
||||
#include "game/GameModel.h"
|
||||
#include "LuaScriptHelper.h"
|
||||
@ -258,7 +261,7 @@ bool LuaScriptInterface::OnMouseWheel(int x, int y, int d)
|
||||
|
||||
bool LuaScriptInterface::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool alt)
|
||||
{
|
||||
int modifiers;
|
||||
int modifiers = 0;
|
||||
if(shift)
|
||||
modifiers |= 0x001;
|
||||
if(ctrl)
|
||||
@ -270,7 +273,7 @@ bool LuaScriptInterface::OnKeyPress(int key, Uint16 character, bool shift, bool
|
||||
|
||||
bool LuaScriptInterface::OnKeyRelease(int key, Uint16 character, bool shift, bool ctrl, bool alt)
|
||||
{
|
||||
int modifiers;
|
||||
int modifiers = 0;
|
||||
if(shift)
|
||||
modifiers |= 0x001;
|
||||
if(ctrl)
|
||||
@ -994,16 +997,8 @@ int luatpt_graphics_func(lua_State *l)
|
||||
|
||||
int luatpt_error(lua_State* l)
|
||||
{
|
||||
/*char *error = "";
|
||||
error = mystrdup((char*)luaL_optstring(l, 1, "Error text"));
|
||||
if(vid_buf!=NULL){
|
||||
error_ui(vid_buf, 0, error);
|
||||
free(error);
|
||||
return 0;
|
||||
}
|
||||
free(error);
|
||||
return luaL_error(l, "Screen buffer does not exist");*/
|
||||
//TODO IMPLEMENT
|
||||
std::string errorMessage = std::string(luaL_optstring(l, 1, "Error text"));
|
||||
new ErrorMessage("Error", errorMessage);
|
||||
return 0;
|
||||
}
|
||||
int luatpt_drawtext(lua_State* l)
|
||||
@ -1539,7 +1534,7 @@ int luatpt_get_property(lua_State* l)
|
||||
|
||||
int luatpt_drawpixel(lua_State* l)
|
||||
{
|
||||
/*int x, y, r, g, b, a;
|
||||
int x, y, r, g, b, a;
|
||||
x = luaL_optint(l, 1, 0);
|
||||
y = luaL_optint(l, 2, 0);
|
||||
r = luaL_optint(l, 3, 255);
|
||||
@ -1557,12 +1552,8 @@ int luatpt_drawpixel(lua_State* l)
|
||||
if (b>255) b = 255;
|
||||
if (a<0) a = 0;
|
||||
if (a>255) a = 255;
|
||||
if (luacon_g->vid!=NULL)
|
||||
{
|
||||
luacon_g->drawpixel(x, y, r, g, b, a);
|
||||
return 0;
|
||||
}*/
|
||||
return luaL_error(l, "Deprecated");
|
||||
luacon_g->blendpixel(x, y, r, g, b, a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luatpt_drawrect(lua_State* l)
|
||||
@ -1672,10 +1663,6 @@ int luatpt_get_name(lua_State* l)
|
||||
|
||||
int luatpt_set_shortcuts(lua_State* l)
|
||||
{
|
||||
/*int state;
|
||||
state = luaL_optint(l, 1, 0);
|
||||
sys_shortcuts = (state==0?0:1);
|
||||
return 0;*/
|
||||
return luaL_error(l, "set_shortcuts: deprecated");
|
||||
}
|
||||
|
||||
@ -1879,20 +1866,9 @@ int luatpt_input(lua_State* l)
|
||||
}
|
||||
int luatpt_message_box(lua_State* l)
|
||||
{
|
||||
/*char *title, *text;
|
||||
title = mystrdup(luaL_optstring(l, 1, "Title"));
|
||||
text = mystrdup(luaL_optstring(l, 2, "Message"));
|
||||
if (vid_buf!=NULL)
|
||||
{
|
||||
info_ui(vid_buf, title, text);
|
||||
free(title);
|
||||
free(text);
|
||||
return 0;
|
||||
}
|
||||
free(title);
|
||||
free(text);
|
||||
return luaL_error(l, "Screen buffer does not exist");;*/
|
||||
//TODO IMPLEMENT
|
||||
std::string title = std::string(luaL_optstring(l, 1, "Title"));
|
||||
std::string message = std::string(luaL_optstring(l, 2, "Message"));
|
||||
new InformationMessage(title, message);
|
||||
return 0;
|
||||
}
|
||||
int luatpt_get_numOfParts(lua_State* l)
|
||||
@ -1945,15 +1921,12 @@ int luatpt_hud(lua_State* l)
|
||||
}
|
||||
int luatpt_gravity(lua_State* l)
|
||||
{
|
||||
//luacon_sim->
|
||||
/*int gravstate;
|
||||
int gravstate;
|
||||
gravstate = luaL_optint(l, 1, 0);
|
||||
if(gravstate)
|
||||
start_grav_async();
|
||||
luacon_sim->grav->start_grav_async();
|
||||
else
|
||||
stop_grav_async();
|
||||
ngrav_enable = (gravstate==0?0:1);*/
|
||||
//TODO IMPLEMENT
|
||||
luacon_sim->grav->stop_grav_async();
|
||||
return 0;
|
||||
}
|
||||
int luatpt_airheat(lua_State* l)
|
||||
@ -1991,7 +1964,7 @@ int luatpt_heat(lua_State* l)
|
||||
int luatpt_cmode_set(lua_State* l)
|
||||
{
|
||||
//TODO IMPLEMENT
|
||||
return luaL_error(l, "Not implemented");
|
||||
return luaL_error(l, "cmode_set: Deprecated");
|
||||
}
|
||||
int luatpt_setfire(lua_State* l)
|
||||
{
|
||||
@ -2002,11 +1975,7 @@ int luatpt_setfire(lua_State* l)
|
||||
}
|
||||
int luatpt_setdebug(lua_State* l)
|
||||
{
|
||||
/*int debug = luaL_optint(l, 1, 0);
|
||||
debug_flags = debug;
|
||||
return 0;*/
|
||||
//TODO IMPLEMENT
|
||||
return luaL_error(l, "Not implemented");
|
||||
return luaL_error(l, "setdebug: Deprecated");
|
||||
}
|
||||
int luatpt_setfpscap(lua_State* l)
|
||||
{
|
||||
@ -2108,32 +2077,30 @@ fin:
|
||||
|
||||
int luatpt_setwindowsize(lua_State* l)
|
||||
{
|
||||
/*int result, scale = luaL_optint(l,1,1), kiosk = luaL_optint(l,2,0);
|
||||
int scale = luaL_optint(l,1,1), kiosk = luaL_optint(l,2,0);
|
||||
if (scale!=2) scale = 1;
|
||||
if (kiosk!=1) kiosk = 0;
|
||||
result = set_scale(scale, kiosk);
|
||||
lua_pushnumber(l, result);
|
||||
return 1;*/
|
||||
//TODO Implement
|
||||
return luaL_error(l, "Not implemented");
|
||||
ui::Engine::Ref().SetScale(scale);
|
||||
ui::Engine::Ref().SetFullscreen(kiosk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luatpt_screenshot(lua_State* l)
|
||||
{
|
||||
//TODO Implement
|
||||
/*int captureUI = luaL_optint(l, 1, 0);
|
||||
if(vid_buf)
|
||||
int captureUI = luaL_optint(l, 1, 0);
|
||||
std::vector<char> data;
|
||||
if(captureUI)
|
||||
{
|
||||
if(captureUI)
|
||||
{
|
||||
dump_frame(vid_buf, XRES+BARSIZE, YRES+MENUSIZE, XRES+BARSIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
dump_frame(vid_buf, XRES, YRES, XRES+BARSIZE);
|
||||
}
|
||||
return 0;
|
||||
}*/
|
||||
return luaL_error(l, "Not implemented");
|
||||
VideoBuffer screenshot(ui::Engine::Ref().g->DumpFrame());
|
||||
data = format::VideoBufferToPNG(screenshot);
|
||||
}
|
||||
else
|
||||
{
|
||||
VideoBuffer screenshot(luacon_ren->DumpFrame());
|
||||
data = format::VideoBufferToPNG(screenshot);
|
||||
}
|
||||
Client::Ref().WriteFile(data, "screenshot.png");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -909,3 +909,12 @@ void Graphics::draw_image(VideoBuffer * vidBuf, int x, int y, int a)
|
||||
draw_image(vidBuf->Buffer, x, y, vidBuf->Width, vidBuf->Height, a);
|
||||
}
|
||||
|
||||
VideoBuffer Graphics::DumpFrame()
|
||||
{
|
||||
#ifdef OGLI
|
||||
#else
|
||||
VideoBuffer newBuffer(XRES+BARSIZE, YRES+MENUSIZE);
|
||||
std::copy(vid, vid+((XRES+BARSIZE)*(YRES+MENUSIZE)), newBuffer.Buffer);
|
||||
return newBuffer;
|
||||
#endif
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#if defined(OGLI)
|
||||
#include "OpenGLHeaders.h"
|
||||
#endif
|
||||
@ -135,6 +136,8 @@ public:
|
||||
static int textwidth(const char *s);
|
||||
static void textsize(const char * s, int & width, int & height);
|
||||
|
||||
VideoBuffer DumpFrame();
|
||||
|
||||
void Acquire();
|
||||
void Release();
|
||||
|
||||
|
@ -2475,6 +2475,23 @@ unsigned int Renderer::GetColourMode()
|
||||
return colour_mode;
|
||||
}
|
||||
|
||||
VideoBuffer Renderer::DumpFrame()
|
||||
{
|
||||
#ifdef OGLR
|
||||
#elif defined(OGLI)
|
||||
VideoBuffer newBuffer(XRES, YRES);
|
||||
std::copy(vid, vid+(XRES*YRES), newBuffer.Buffer);
|
||||
return newBuffer;
|
||||
#else
|
||||
VideoBuffer newBuffer(XRES, YRES);
|
||||
for(int y = 0; y < YRES; y++)
|
||||
{
|
||||
std::copy(vid+(y*(XRES+BARSIZE)), vid+(y*(XRES+BARSIZE))+XRES, newBuffer.Buffer+(y*XRES));
|
||||
}
|
||||
return newBuffer;
|
||||
#endif
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
{
|
||||
#if !defined(OGLR)
|
||||
|
@ -113,6 +113,8 @@ public:
|
||||
void draw_image(pixel *img, int x, int y, int w, int h, int a);
|
||||
#endif
|
||||
|
||||
VideoBuffer DumpFrame();
|
||||
|
||||
void drawblob(int x, int y, unsigned char cr, unsigned char cg, unsigned char cb);
|
||||
//...
|
||||
//Display mode modifiers
|
||||
|
Reference in New Issue
Block a user