Implement some missing lua functions, PNG format creation (requires zlib)

This commit is contained in:
Simon Robertshaw 2012-08-11 20:24:48 +01:00
parent ecbb1e9103
commit 08b4e5553a
8 changed files with 337 additions and 69 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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();

View File

@ -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)

View File

@ -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