mirror of
https://github.com/glest/glest-source.git
synced 2025-08-11 19:04:00 +02:00
- added new default PNG format for doing screenshots AND the saving to disk is queued in a background thread allowing almost no delay when saving many screenshots!
This commit is contained in:
@@ -1197,13 +1197,15 @@ void Game::keyDown(char key) {
|
|||||||
string path = GameConstants::folder_path_screenshots;
|
string path = GameConstants::folder_path_screenshots;
|
||||||
if(isdir(path.c_str()) == true) {
|
if(isdir(path.c_str()) == true) {
|
||||||
Config &config= Config::getInstance();
|
Config &config= Config::getInstance();
|
||||||
string fileFormat = config.getString("ScreenShotFileType","bmp");
|
string fileFormat = config.getString("ScreenShotFileType","png");
|
||||||
|
|
||||||
for(int i=0; i<250; ++i){
|
unsigned int queueSize = Renderer::getInstance().getSaveScreenQueueSize();
|
||||||
|
|
||||||
|
for(int i=0; i < 250; ++i) {
|
||||||
path = GameConstants::folder_path_screenshots;
|
path = GameConstants::folder_path_screenshots;
|
||||||
path += "screen" + intToStr(i) + "." + fileFormat;
|
path += "screen" + intToStr(i + queueSize) + "." + fileFormat;
|
||||||
FILE *f= fopen(path.c_str(), "rb");
|
FILE *f= fopen(path.c_str(), "rb");
|
||||||
if(f==NULL) {
|
if(f == NULL) {
|
||||||
Renderer::getInstance().saveScreen(path);
|
Renderer::getInstance().saveScreen(path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -152,12 +152,11 @@ Renderer::Renderer() {
|
|||||||
modelRenderer = NULL;
|
modelRenderer = NULL;
|
||||||
textRenderer = NULL;
|
textRenderer = NULL;
|
||||||
particleRenderer = NULL;
|
particleRenderer = NULL;
|
||||||
|
saveScreenShotThread = NULL;
|
||||||
|
|
||||||
lastRenderFps=MIN_FPS_NORMAL_RENDERING;
|
lastRenderFps=MIN_FPS_NORMAL_RENDERING;
|
||||||
shadowsOffDueToMinRender=false;
|
shadowsOffDueToMinRender=false;
|
||||||
|
|
||||||
pixmapScreenShot = NULL;;
|
|
||||||
|
|
||||||
//resources
|
//resources
|
||||||
for(int i=0; i < rsCount; ++i) {
|
for(int i=0; i < rsCount; ++i) {
|
||||||
modelManager[i] = NULL;
|
modelManager[i] = NULL;
|
||||||
@@ -189,9 +188,13 @@ Renderer::Renderer() {
|
|||||||
particleManager[i]= graphicsFactory->newParticleManager();
|
particleManager[i]= graphicsFactory->newParticleManager();
|
||||||
fontManager[i]= graphicsFactory->newFontManager();
|
fontManager[i]= graphicsFactory->newFontManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
saveScreenShotThread = new SimpleTaskThread(this,0,25);
|
||||||
|
saveScreenShotThread->setUniqueID(__FILE__);
|
||||||
|
saveScreenShotThread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer::~Renderer(){
|
Renderer::~Renderer() {
|
||||||
delete modelRenderer;
|
delete modelRenderer;
|
||||||
modelRenderer = NULL;
|
modelRenderer = NULL;
|
||||||
delete textRenderer;
|
delete textRenderer;
|
||||||
@@ -211,12 +214,50 @@ Renderer::~Renderer(){
|
|||||||
fontManager[i] = NULL;
|
fontManager[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete pixmapScreenShot;
|
// Wait for the queue to become empty or timeout the thread at 7 seconds
|
||||||
|
for(time_t elapsed = time(NULL);
|
||||||
|
getSaveScreenQueueSize() > 0 && difftime(time(NULL),elapsed) <= 7;) {
|
||||||
|
sleep(10);
|
||||||
|
}
|
||||||
|
delete saveScreenShotThread;
|
||||||
|
saveScreenShotThread = NULL;
|
||||||
|
|
||||||
|
if(getSaveScreenQueueSize() > 0) {
|
||||||
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d] FORCING MEMORY CLEANUP and NOT SAVING screenshots, saveScreenQueue.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,saveScreenQueue.size());
|
||||||
|
|
||||||
|
for(std::list<std::pair<string,Pixmap2D *> >::iterator iter = saveScreenQueue.begin();
|
||||||
|
iter != saveScreenQueue.end(); ++iter) {
|
||||||
|
delete iter->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->menu = NULL;
|
this->menu = NULL;
|
||||||
this->game = NULL;
|
this->game = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::simpleTask() {
|
||||||
|
// This code reads pixmaps from a queue and saves them to disk
|
||||||
|
Pixmap2D *savePixMapBuffer=NULL;
|
||||||
|
string path="";
|
||||||
|
MutexSafeWrapper safeMutex(&saveScreenShotThreadAccessor);
|
||||||
|
if(saveScreenQueue.size() > 0) {
|
||||||
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d] saveScreenQueue.size() = %d\n",__FILE__,__FUNCTION__,__LINE__,saveScreenQueue.size());
|
||||||
|
|
||||||
|
savePixMapBuffer = saveScreenQueue.front().second;
|
||||||
|
path = saveScreenQueue.front().first;
|
||||||
|
|
||||||
|
saveScreenQueue.pop_front();
|
||||||
|
}
|
||||||
|
safeMutex.ReleaseLock();
|
||||||
|
|
||||||
|
if(savePixMapBuffer != NULL) {
|
||||||
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d] about to save [%s]\n",__FILE__,__FUNCTION__,__LINE__,path.c_str());
|
||||||
|
|
||||||
|
savePixMapBuffer->save(path);
|
||||||
|
delete savePixMapBuffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Renderer &Renderer::getInstance(){
|
Renderer &Renderer::getInstance(){
|
||||||
static Renderer renderer;
|
static Renderer renderer;
|
||||||
return renderer;
|
return renderer;
|
||||||
@@ -2945,21 +2986,13 @@ void Renderer::loadConfig(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::saveScreen(const string &path){
|
void Renderer::saveScreen(const string &path) {
|
||||||
|
|
||||||
const Metrics &sm= Metrics::getInstance();
|
const Metrics &sm= Metrics::getInstance();
|
||||||
|
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||||
|
|
||||||
//Pixmap2D pixmap(sm.getScreenW(), sm.getScreenH(), 3);
|
//Pixmap2D pixmap(sm.getScreenW(), sm.getScreenH(), 3);
|
||||||
if( pixmapScreenShot == NULL ||
|
Pixmap2D *pixmapScreenShot = new Pixmap2D(sm.getScreenW(), sm.getScreenH(), 3);
|
||||||
pixmapScreenShot->getW() != sm.getScreenW() ||
|
|
||||||
pixmapScreenShot->getH() != sm.getScreenH()) {
|
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
|
||||||
|
|
||||||
delete pixmapScreenShot;
|
|
||||||
pixmapScreenShot = new Pixmap2D(sm.getScreenW(), sm.getScreenH(), 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||||
glFinish();
|
glFinish();
|
||||||
@@ -2969,11 +3002,23 @@ void Renderer::saveScreen(const string &path){
|
|||||||
GL_RGB, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
|
GL_RGB, GL_UNSIGNED_BYTE, pixmapScreenShot->getPixels());
|
||||||
|
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||||
pixmapScreenShot->save(path);
|
|
||||||
|
// Signal the threads queue to add a screenshot save request
|
||||||
|
MutexSafeWrapper safeMutex(&saveScreenShotThreadAccessor);
|
||||||
|
saveScreenQueue.push_back(make_pair(path,pixmapScreenShot));
|
||||||
|
safeMutex.ReleaseLock();
|
||||||
|
|
||||||
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int Renderer::getSaveScreenQueueSize() {
|
||||||
|
MutexSafeWrapper safeMutex(&saveScreenShotThreadAccessor);
|
||||||
|
int queueSize = saveScreenQueue.size();
|
||||||
|
safeMutex.ReleaseLock();
|
||||||
|
|
||||||
|
return queueSize;
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== PRIVATE ====================
|
// ==================== PRIVATE ====================
|
||||||
|
|
||||||
float Renderer::computeSunAngle(float time) {
|
float Renderer::computeSunAngle(float time) {
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "graphics_interface.h"
|
#include "graphics_interface.h"
|
||||||
#include "base_renderer.h"
|
#include "base_renderer.h"
|
||||||
|
#include "simple_threads.h"
|
||||||
|
|
||||||
#ifdef DEBUG_RENDERING_ENABLED
|
#ifdef DEBUG_RENDERING_ENABLED
|
||||||
# define IF_DEBUG_EDITION(x) x
|
# define IF_DEBUG_EDITION(x) x
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
namespace Glest{ namespace Game{
|
namespace Glest{ namespace Game{
|
||||||
|
|
||||||
using namespace Shared::Graphics;
|
using namespace Shared::Graphics;
|
||||||
|
using namespace Shared::PlatformCommon;
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// class MeshCallbackTeamColor
|
// class MeshCallbackTeamColor
|
||||||
@@ -131,7 +133,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Renderer : public RendererInterface, public BaseRenderer {
|
class Renderer : public RendererInterface, public BaseRenderer, public SimpleTaskCallbackInterface {
|
||||||
public:
|
public:
|
||||||
//progress bar
|
//progress bar
|
||||||
static const int maxProgressBar;
|
static const int maxProgressBar;
|
||||||
@@ -242,7 +244,9 @@ private:
|
|||||||
|
|
||||||
bool useQuadCache;
|
bool useQuadCache;
|
||||||
|
|
||||||
Pixmap2D *pixmapScreenShot;
|
SimpleTaskThread *saveScreenShotThread;
|
||||||
|
Mutex saveScreenShotThreadAccessor;
|
||||||
|
std::list<std::pair<string,Pixmap2D *> > saveScreenQueue;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Renderer();
|
Renderer();
|
||||||
@@ -386,6 +390,7 @@ public:
|
|||||||
void removeUnitFromQuadCache(const Unit *unit);
|
void removeUnitFromQuadCache(const Unit *unit);
|
||||||
|
|
||||||
uint64 getCurrentPixelByteCount(ResourceScope rs=rsGame) const;
|
uint64 getCurrentPixelByteCount(ResourceScope rs=rsGame) const;
|
||||||
|
unsigned int getSaveScreenQueueSize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//private misc
|
//private misc
|
||||||
@@ -421,6 +426,8 @@ private:
|
|||||||
void renderTile(const Vec2i &pos);
|
void renderTile(const Vec2i &pos);
|
||||||
void renderQuad(int x, int y, int w, int h, const Texture2D *texture);
|
void renderQuad(int x, int y, int w, int h, const Texture2D *texture);
|
||||||
|
|
||||||
|
void simpleTask();
|
||||||
|
|
||||||
//static
|
//static
|
||||||
static Texture2D::Filter strToTextureFilter(const string &s);
|
static Texture2D::Filter strToTextureFilter(const string &s);
|
||||||
};
|
};
|
||||||
|
@@ -33,7 +33,7 @@ namespace Shared{ namespace Graphics{
|
|||||||
// class PixmapIo
|
// class PixmapIo
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
class PixmapIo{
|
class PixmapIo {
|
||||||
protected:
|
protected:
|
||||||
int w;
|
int w;
|
||||||
int h;
|
int h;
|
||||||
@@ -58,7 +58,7 @@ public:
|
|||||||
// class PixmapIoTga
|
// class PixmapIoTga
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
class PixmapIoTga: public PixmapIo{
|
class PixmapIoTga: public PixmapIo {
|
||||||
private:
|
private:
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ public:
|
|||||||
// class PixmapIoBmp
|
// class PixmapIoBmp
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
class PixmapIoBmp: public PixmapIo{
|
class PixmapIoBmp: public PixmapIo {
|
||||||
private:
|
private:
|
||||||
FILE *file;
|
FILE *file;
|
||||||
|
|
||||||
@@ -94,6 +94,27 @@ public:
|
|||||||
virtual void write(uint8 *pixels);
|
virtual void write(uint8 *pixels);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class PixmapIoBmp
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
class PixmapIoPng: public PixmapIo {
|
||||||
|
private:
|
||||||
|
FILE *file;
|
||||||
|
string path;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PixmapIoPng();
|
||||||
|
virtual ~PixmapIoPng();
|
||||||
|
|
||||||
|
virtual void openRead(const string &path);
|
||||||
|
virtual void read(uint8 *pixels);
|
||||||
|
virtual void read(uint8 *pixels, int components);
|
||||||
|
|
||||||
|
virtual void openWrite(const string &path, int w, int h, int components);
|
||||||
|
virtual void write(uint8 *pixels);
|
||||||
|
};
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// class Pixmap1D
|
// class Pixmap1D
|
||||||
// =====================================================
|
// =====================================================
|
||||||
@@ -157,7 +178,7 @@ public:
|
|||||||
void save(const string &path);
|
void save(const string &path);
|
||||||
void saveBmp(const string &path);
|
void saveBmp(const string &path);
|
||||||
void saveTga(const string &path);
|
void saveTga(const string &path);
|
||||||
|
void savePng(const string &path);
|
||||||
|
|
||||||
//get
|
//get
|
||||||
int getW() const {return w;}
|
int getW() const {return w;}
|
||||||
|
@@ -21,6 +21,8 @@
|
|||||||
#include "randomgen.h"
|
#include "randomgen.h"
|
||||||
#include "FileReader.h"
|
#include "FileReader.h"
|
||||||
#include "ImageReaders.h"
|
#include "ImageReaders.h"
|
||||||
|
#include <png.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
#include "leak_dumper.h"
|
#include "leak_dumper.h"
|
||||||
|
|
||||||
@@ -285,7 +287,7 @@ void PixmapIoBmp::openWrite(const string &path, int w, int h, int components) {
|
|||||||
|
|
||||||
file= fopen(path.c_str(),"wb");
|
file= fopen(path.c_str(),"wb");
|
||||||
if (file == NULL) {
|
if (file == NULL) {
|
||||||
throw runtime_error("Can't open BMP file for writting: "+ path);
|
throw runtime_error("Can't open BMP file for writing: "+ path);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitmapFileHeader fileHeader;
|
BitmapFileHeader fileHeader;
|
||||||
@@ -321,6 +323,210 @@ void PixmapIoBmp::write(uint8 *pixels) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =====================================================
|
||||||
|
// class PixmapIoPng
|
||||||
|
// =====================================================
|
||||||
|
|
||||||
|
PixmapIoPng::PixmapIoPng() {
|
||||||
|
file= NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PixmapIoPng::~PixmapIoPng() {
|
||||||
|
if(file!=NULL){
|
||||||
|
fclose(file);
|
||||||
|
file=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixmapIoPng::openRead(const string &path) {
|
||||||
|
|
||||||
|
throw runtime_error("PixmapIoPng::openRead not implemented!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
file= fopen(path.c_str(),"rb");
|
||||||
|
if (file==NULL){
|
||||||
|
throw runtime_error("Can't open BMP file: "+ path);
|
||||||
|
}
|
||||||
|
|
||||||
|
//read file header
|
||||||
|
BitmapFileHeader fileHeader;
|
||||||
|
size_t readBytes = fread(&fileHeader, sizeof(BitmapFileHeader), 1, file);
|
||||||
|
if(fileHeader.type1!='B' || fileHeader.type2!='M'){
|
||||||
|
throw runtime_error(path +" is not a bitmap");
|
||||||
|
}
|
||||||
|
|
||||||
|
//read info header
|
||||||
|
BitmapInfoHeader infoHeader;
|
||||||
|
readBytes = fread(&infoHeader, sizeof(BitmapInfoHeader), 1, file);
|
||||||
|
if(infoHeader.bitCount!=24){
|
||||||
|
throw runtime_error(path+" is not a 24 bit bitmap");
|
||||||
|
}
|
||||||
|
|
||||||
|
h= infoHeader.height;
|
||||||
|
w= infoHeader.width;
|
||||||
|
components= 3;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixmapIoPng::read(uint8 *pixels) {
|
||||||
|
throw runtime_error("PixmapIoPng::read not implemented!");
|
||||||
|
//read(pixels, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixmapIoPng::read(uint8 *pixels, int components) {
|
||||||
|
|
||||||
|
throw runtime_error("PixmapIoPng::read #2 not implemented!");
|
||||||
|
|
||||||
|
/*
|
||||||
|
for(int i=0; i<h*w*components; i+=components) {
|
||||||
|
uint8 r, g, b;
|
||||||
|
size_t readBytes = fread(&b, 1, 1, file);
|
||||||
|
readBytes = fread(&g, 1, 1, file);
|
||||||
|
readBytes = fread(&r, 1, 1, file);
|
||||||
|
|
||||||
|
switch(components){
|
||||||
|
case 1:
|
||||||
|
pixels[i]= (r+g+b)/3;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pixels[i]= r;
|
||||||
|
pixels[i+1]= g;
|
||||||
|
pixels[i+2]= b;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
pixels[i]= r;
|
||||||
|
pixels[i+1]= g;
|
||||||
|
pixels[i+2]= b;
|
||||||
|
pixels[i+3]= 255;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixmapIoPng::openWrite(const string &path, int w, int h, int components) {
|
||||||
|
this->path = path;
|
||||||
|
this->w= w;
|
||||||
|
this->h= h;
|
||||||
|
this->components= components;
|
||||||
|
|
||||||
|
file= fopen(path.c_str(),"wb");
|
||||||
|
if (file == NULL) {
|
||||||
|
throw runtime_error("Can't open PNG file for writing: "+ path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PixmapIoPng::write(uint8 *pixels) {
|
||||||
|
// Allocate write & info structures
|
||||||
|
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if(!png_ptr) {
|
||||||
|
fclose(file);
|
||||||
|
throw runtime_error("OpenGlDevice::saveImageAsPNG() - out of memory creating write structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if(!info_ptr) {
|
||||||
|
png_destroy_write_struct(&png_ptr,
|
||||||
|
(png_infopp)NULL);
|
||||||
|
fclose(file);
|
||||||
|
throw runtime_error("OpenGlDevice::saveImageAsPNG() - out of memery creating info structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
// setjmp() must be called in every function that calls a PNG-writing
|
||||||
|
// libpng function, unless an alternate error handler was installed--
|
||||||
|
// but compatible error handlers must either use longjmp() themselves
|
||||||
|
// (as in this program) or exit immediately, so here we go: */
|
||||||
|
|
||||||
|
if(setjmp(png_jmpbuf(png_ptr))) {
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
fclose(file);
|
||||||
|
throw runtime_error("OpenGlDevice::saveImageAsPNG() - setjmp problem");
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure outfile is (re)opened in BINARY mode
|
||||||
|
png_init_io(png_ptr, file);
|
||||||
|
|
||||||
|
// set the compression levels--in general, always want to leave filtering
|
||||||
|
// turned on (except for palette images) and allow all of the filters,
|
||||||
|
// which is the default; want 32K zlib window, unless entire image buffer
|
||||||
|
// is 16K or smaller (unknown here)--also the default; usually want max
|
||||||
|
// compression (NOT the default); and remaining compression flags should
|
||||||
|
// be left alone
|
||||||
|
|
||||||
|
//png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
|
||||||
|
png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION);
|
||||||
|
|
||||||
|
//
|
||||||
|
// this is default for no filtering; Z_FILTERED is default otherwise:
|
||||||
|
// png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
|
||||||
|
// these are all defaults:
|
||||||
|
// png_set_compression_mem_level(png_ptr, 8);
|
||||||
|
// png_set_compression_window_bits(png_ptr, 15);
|
||||||
|
// png_set_compression_method(png_ptr, 8);
|
||||||
|
|
||||||
|
|
||||||
|
// Set some options: color_type, interlace_type
|
||||||
|
int color_type=0, interlace_type=0, numChannels=0;
|
||||||
|
|
||||||
|
// color_type = PNG_COLOR_TYPE_GRAY;
|
||||||
|
// color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
|
||||||
|
color_type = PNG_COLOR_TYPE_RGB;
|
||||||
|
numChannels = 3;
|
||||||
|
// color_type = PNG_COLOR_TYPE_RGB_ALPHA;
|
||||||
|
|
||||||
|
interlace_type = PNG_INTERLACE_NONE;
|
||||||
|
// interlace_type = PNG_INTERLACE_ADAM7;
|
||||||
|
|
||||||
|
int bit_depth = 8;
|
||||||
|
png_set_IHDR(png_ptr, info_ptr, this->w, this->h, bit_depth,
|
||||||
|
color_type,
|
||||||
|
interlace_type,
|
||||||
|
PNG_COMPRESSION_TYPE_BASE,
|
||||||
|
PNG_FILTER_TYPE_BASE);
|
||||||
|
|
||||||
|
// Optional gamma chunk is strongly suggested if you have any guess
|
||||||
|
// as to the correct gamma of the image. (we don't have a guess)
|
||||||
|
//
|
||||||
|
// png_set_gAMA(png_ptr, info_ptr, image_gamma);
|
||||||
|
|
||||||
|
// write all chunks up to (but not including) first IDAT
|
||||||
|
png_write_info(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
// set up the row pointers for the image so we can use png_write_image
|
||||||
|
|
||||||
|
png_bytep* row_pointers = new png_bytep[this->h];
|
||||||
|
if (row_pointers == 0) {
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
fclose(file);
|
||||||
|
throw runtime_error("OpenGlDevice::failed to allocate memory for row pointers");
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int row_stride = this->w * numChannels;
|
||||||
|
unsigned char *rowptr = (unsigned char*) pixels;
|
||||||
|
for (int row = this->h-1; row >=0 ; row--) {
|
||||||
|
row_pointers[row] = rowptr;
|
||||||
|
rowptr += row_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we just write the whole image; libpng takes care of interlacing for us
|
||||||
|
png_write_image(png_ptr, row_pointers);
|
||||||
|
|
||||||
|
// since that's it, we also close out the end of the PNG file now--if we
|
||||||
|
// had any text or time info to write after the IDATs, second argument
|
||||||
|
// would be info_ptr, but we optimize slightly by sending NULL pointer: */
|
||||||
|
|
||||||
|
png_write_end(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
//
|
||||||
|
// clean up after the write
|
||||||
|
// free any memory allocated & close the file
|
||||||
|
//
|
||||||
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||||
|
|
||||||
|
delete [] row_pointers;
|
||||||
|
//fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// class Pixmap1D
|
// class Pixmap1D
|
||||||
// =====================================================
|
// =====================================================
|
||||||
@@ -512,6 +718,9 @@ void Pixmap2D::save(const string &path) {
|
|||||||
else if(toLower(extension) == "tga") {
|
else if(toLower(extension) == "tga") {
|
||||||
saveTga(path);
|
saveTga(path);
|
||||||
}
|
}
|
||||||
|
else if(toLower(extension) == "png") {
|
||||||
|
savePng(path);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throw runtime_error("Unknown pixmap extension: " + extension);
|
throw runtime_error("Unknown pixmap extension: " + extension);
|
||||||
}
|
}
|
||||||
@@ -528,7 +737,12 @@ void Pixmap2D::saveTga(const string &path) {
|
|||||||
pst.openWrite(path, w, h, components);
|
pst.openWrite(path, w, h, components);
|
||||||
pst.write(pixels);
|
pst.write(pixels);
|
||||||
}
|
}
|
||||||
|
void Pixmap2D::savePng(const string &path) {
|
||||||
|
PixmapIoPng pst;
|
||||||
|
pst.openWrite(path, w, h, components);
|
||||||
|
pst.write(pixels);
|
||||||
|
|
||||||
|
}
|
||||||
void Pixmap2D::getPixel(int x, int y, uint8 *value) const {
|
void Pixmap2D::getPixel(int x, int y, uint8 *value) const {
|
||||||
for(int i=0; i<components; ++i){
|
for(int i=0; i<components; ++i){
|
||||||
value[i]= pixels[(w*y+x)*components+i];
|
value[i]= pixels[(w*y+x)*components+i];
|
||||||
|
Reference in New Issue
Block a user