mirror of https://github.com/stella-emu/stella.git
Merge branch 'master' into feature/filesystem
This commit is contained in:
commit
a55b1a2767
|
@ -807,6 +807,7 @@ DBGGUI="$SRC/debugger/gui"
|
|||
YACC="$SRC/yacc"
|
||||
CHEAT="$SRC/cheat"
|
||||
LIBPNG="$SRC/libpng"
|
||||
LIBJPG="$SRC/nanojpeg"
|
||||
ZLIB="$SRC/zlib"
|
||||
SQLITE_REPO="$SRC/common/repository/sqlite"
|
||||
SQLITE_LIB="$SRC/sqlite"
|
||||
|
@ -893,7 +894,8 @@ if test "$_build_httplib" = yes ; then
|
|||
fi
|
||||
|
||||
if test "$_build_png" = yes ; then
|
||||
DEFINES="$DEFINES -DPNG_SUPPORT"
|
||||
DEFINES="$DEFINES -DIMAGE_SUPPORT"
|
||||
INCLUDES="$INCLUDES -I$LIBJPG"
|
||||
if test "$_libpng" = yes ; then
|
||||
LIBS="$LIBS `pkg-config --libs libpng`"
|
||||
else
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifdef IMAGE_SUPPORT
|
||||
|
||||
#include "OSystem.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "nanojpeg_lib.hxx"
|
||||
|
||||
#include "JPGLibrary.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
JPGLibrary::JPGLibrary(OSystem& osystem)
|
||||
: myOSystem{osystem}
|
||||
{
|
||||
njInit();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JPGLibrary::loadImage(const string& filename, FBSurface& surface,
|
||||
VariantList& comments)
|
||||
{
|
||||
const auto loadImageERROR = [&](const char* s) {
|
||||
if(s)
|
||||
throw runtime_error(s);
|
||||
};
|
||||
|
||||
std::ifstream in(filename, std::ios_base::binary | std::ios::ate);
|
||||
if(!in.is_open())
|
||||
loadImageERROR("No image found");
|
||||
const size_t size = in.tellg();
|
||||
in.clear();
|
||||
in.seekg(0);
|
||||
|
||||
// Create space for the entire file
|
||||
if(size > myFileBuffer.size())
|
||||
myFileBuffer.resize(size);
|
||||
if(!in.read(myFileBuffer.data(), size))
|
||||
loadImageERROR("Image data reading failed");
|
||||
in.close();
|
||||
|
||||
if(njDecode(myFileBuffer.data(), static_cast<int>(size)))
|
||||
loadImageERROR("Error decoding the input file");
|
||||
|
||||
// Read the entire image in one go
|
||||
myReadInfo.buffer = njGetImage();
|
||||
myReadInfo.width = njGetWidth();
|
||||
myReadInfo.height = njGetHeight();
|
||||
myReadInfo.pitch = myReadInfo.width * 3;
|
||||
|
||||
// Read the comments we got TODO
|
||||
//readComments(png_ptr, info_ptr, comments);
|
||||
|
||||
// Load image into the surface, setting the correct dimensions
|
||||
loadImagetoSurface(surface);
|
||||
|
||||
// Cleanup
|
||||
njDone();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void JPGLibrary::loadImagetoSurface(FBSurface& surface)
|
||||
{
|
||||
// First determine if we need to resize the surface
|
||||
const uInt32 iw = myReadInfo.width, ih = myReadInfo.height;
|
||||
if(iw > surface.width() || ih > surface.height())
|
||||
surface.resize(iw, ih);
|
||||
|
||||
// The source dimensions are set here; the destination dimensions are
|
||||
// set by whoever owns the surface
|
||||
surface.setSrcPos(0, 0);
|
||||
surface.setSrcSize(iw, ih);
|
||||
|
||||
// Convert RGB triples into pixels and store in the surface
|
||||
uInt32* s_buf, s_pitch;
|
||||
surface.basePtr(s_buf, s_pitch);
|
||||
const uInt8* i_buf = myReadInfo.buffer;
|
||||
const uInt32 i_pitch = myReadInfo.pitch;
|
||||
|
||||
const FrameBuffer& fb = myOSystem.frameBuffer();
|
||||
for(uInt32 irow = 0; irow < ih; ++irow, i_buf += i_pitch, s_buf += s_pitch)
|
||||
{
|
||||
const uInt8* i_ptr = i_buf;
|
||||
uInt32* s_ptr = s_buf;
|
||||
for(uInt32 icol = 0; icol < myReadInfo.width; ++icol, i_ptr += 3)
|
||||
*s_ptr++ = fb.mapRGB(*i_ptr, *(i_ptr + 1), *(i_ptr + 2));
|
||||
}
|
||||
}
|
||||
|
||||
//// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
//void JPGLibrary::readComments(const png_structp png_ptr, png_infop info_ptr,
|
||||
// VariantList& comments)
|
||||
//{
|
||||
// png_textp text_ptr;
|
||||
// int numComments = 0;
|
||||
//
|
||||
// // TODO: currently works only if comments are *before* the image data
|
||||
// png_get_text(png_ptr, info_ptr, &text_ptr, &numComments);
|
||||
//
|
||||
// comments.clear();
|
||||
// for(int i = 0; i < numComments; ++i)
|
||||
// {
|
||||
// VarList::push_back(comments, text_ptr[i].key, text_ptr[i].text);
|
||||
// }
|
||||
//}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
std::vector<char> JPGLibrary::myFileBuffer;
|
||||
|
||||
#endif // IMAGE_SUPPORT
|
|
@ -0,0 +1,89 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifdef IMAGE_SUPPORT
|
||||
|
||||
#ifndef JPG_LIBRARY_HXX
|
||||
#define JPG_LIBRARY_HXX
|
||||
|
||||
class OSystem;
|
||||
class FBSurface;
|
||||
|
||||
/**
|
||||
This class implements a thin wrapper around the nanojpeg library, and
|
||||
abstracts all the irrelevant details other loading an actual image.
|
||||
|
||||
@author Thomas Jentzsch
|
||||
*/
|
||||
class JPGLibrary
|
||||
{
|
||||
public:
|
||||
explicit JPGLibrary(OSystem& osystem);
|
||||
|
||||
/**
|
||||
Read a JPG image from the specified file into a FBSurface structure,
|
||||
scaling the image to the surface bounds.
|
||||
|
||||
@param filename The filename to load the JPG image
|
||||
@param surface The FBSurface into which to place the JPG data
|
||||
|
||||
@post On success, the FBSurface containing image data, otherwise a
|
||||
runtime_error is thrown containing a more detailed
|
||||
error message.
|
||||
*/
|
||||
void loadImage(const string& filename, FBSurface& surface, VariantList& comments);
|
||||
|
||||
private:
|
||||
// Global OSystem object
|
||||
OSystem& myOSystem;
|
||||
|
||||
// The following data remains between invocations of allocateStorage,
|
||||
// and is only changed when absolutely necessary.
|
||||
struct ReadInfoType {
|
||||
unsigned char* buffer;
|
||||
//vector<unsigned char> buffer;
|
||||
uInt32 width{0}, height{0}, pitch{0};
|
||||
};
|
||||
ReadInfoType myReadInfo;
|
||||
static std::vector<char> myFileBuffer;
|
||||
|
||||
/**
|
||||
Load the JPG data from 'ReadInfo' into the FBSurface. The surface
|
||||
is resized as necessary to accommodate the data.
|
||||
|
||||
@param surface The FBSurface into which to place the JPG data
|
||||
*/
|
||||
void loadImagetoSurface(FBSurface& surface);
|
||||
|
||||
///**
|
||||
// Read EXIF metadata chunks from the image.
|
||||
//*/
|
||||
//void readComments(const png_structp png_ptr, png_infop info_ptr,
|
||||
// VariantList& comments);
|
||||
|
||||
private:
|
||||
// Following constructors and assignment operators not supported
|
||||
JPGLibrary() = delete;
|
||||
JPGLibrary(const JPGLibrary&) = delete;
|
||||
JPGLibrary(JPGLibrary&&) = delete;
|
||||
JPGLibrary& operator=(const JPGLibrary&) = delete;
|
||||
JPGLibrary& operator=(JPGLibrary&&) = delete;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // IMAGE_SUPPORT
|
|
@ -709,7 +709,7 @@ PhysicalKeyboardHandler::DefaultCommonMapping = {
|
|||
{ Event::ToggleFrameStats, KBDK_L, MOD3 },
|
||||
{ Event::ToggleTimeMachine, KBDK_T, MOD3 },
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
{ Event::ToggleContSnapshots, KBDK_S, MOD3 | KBDM_CTRL },
|
||||
{ Event::ToggleContSnapshotsFrame, KBDK_S, KBDM_SHIFT | MOD3 | KBDM_CTRL },
|
||||
#endif
|
||||
|
|
|
@ -15,21 +15,16 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#if defined(PNG_SUPPORT)
|
||||
#ifdef IMAGE_SUPPORT
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "FrameBuffer.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "Props.hxx"
|
||||
#include "Settings.hxx"
|
||||
#include "TIASurface.hxx"
|
||||
#include "Version.hxx"
|
||||
#include "PNGLibrary.hxx"
|
||||
#include "Rect.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PNGLibrary::PNGLibrary(OSystem& osystem)
|
||||
|
@ -504,4 +499,4 @@ void PNGLibrary::png_user_error(const png_structp ctx, png_const_charp str)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
PNGLibrary::ReadInfoType PNGLibrary::ReadInfo;
|
||||
|
||||
#endif // PNG_SUPPORT
|
||||
#endif // IMAGE_SUPPORT
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#if defined(PNG_SUPPORT)
|
||||
#ifdef IMAGE_SUPPORT
|
||||
|
||||
#ifndef PNGLIBRARY_HXX
|
||||
#define PNGLIBRARY_HXX
|
||||
|
@ -23,11 +23,7 @@
|
|||
#include <png.h>
|
||||
|
||||
class OSystem;
|
||||
class FrameBuffer;
|
||||
class FBSurface;
|
||||
class Properties;
|
||||
|
||||
#include "bspf.hxx"
|
||||
|
||||
/**
|
||||
This class implements a thin wrapper around the libpng library, and
|
||||
|
@ -207,4 +203,4 @@ class PNGLibrary
|
|||
|
||||
#endif
|
||||
|
||||
#endif // PNG_SUPPORT
|
||||
#endif // IMAGE_SUPPORT
|
||||
|
|
|
@ -13,6 +13,7 @@ MODULE_OBJS := \
|
|||
src/common/FSNodeZIP.o \
|
||||
src/common/HighScoresManager.o \
|
||||
src/common/JoyMap.o \
|
||||
src/common/JPGLibrary.o \
|
||||
src/common/KeyMap.o \
|
||||
src/common/Logger.o \
|
||||
src/common/main.o \
|
||||
|
|
|
@ -47,7 +47,7 @@ TiaOutputWidget::TiaOutputWidget(GuiObject* boss, const GUI::Font& font,
|
|||
VarList::push_back(l, "Fill to scanline", "scanline");
|
||||
VarList::push_back(l, "Toggle breakpoint", "bp");
|
||||
VarList::push_back(l, "Set zoom position", "zoom");
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
VarList::push_back(l, "Save snapshot", "snap");
|
||||
#endif
|
||||
myMenu = make_unique<ContextMenu>(this, font, l);
|
||||
|
@ -65,7 +65,7 @@ void TiaOutputWidget::loadConfig()
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void TiaOutputWidget::saveSnapshot(int execDepth, const string& execPrefix)
|
||||
{
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
if(execDepth > 0)
|
||||
drawWidget(false);
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ void EventHandler::reset(EventHandlerState state)
|
|||
{
|
||||
setState(state);
|
||||
myOSystem.state().reset();
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
myOSystem.png().setContinuousSnapInterval(0);
|
||||
#endif
|
||||
myFryingFlag = false;
|
||||
|
@ -274,7 +274,7 @@ void EventHandler::poll(uInt64 time)
|
|||
cheat->evaluate();
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
// Handle continuous snapshots
|
||||
if(myOSystem.png().continuousSnapEnabled())
|
||||
myOSystem.png().updateTime(time);
|
||||
|
@ -1495,7 +1495,7 @@ void EventHandler::handleEvent(Event::Type event, Int32 value, bool repeated)
|
|||
if(pressed && !repeated) myOSystem.toggleTimeMachine();
|
||||
return;
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
case Event::ToggleContSnapshots:
|
||||
if(pressed && !repeated) myOSystem.png().toggleContinuousSnapshots(false);
|
||||
return;
|
||||
|
@ -2827,7 +2827,7 @@ EventHandler::EmulActionList EventHandler::ourEmulActionList = { {
|
|||
{ Event::LoadState, "Load state" },
|
||||
{ Event::LoadAllStates, "Load saved TM states for current game" },
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
{ Event::TakeSnapshot, "Snapshot" },
|
||||
{ Event::ToggleContSnapshots, "Save continuous snapsh. (as defined)" },
|
||||
{ Event::ToggleContSnapshotsFrame,"Save continuous snapsh. (every frame)" },
|
||||
|
|
|
@ -514,7 +514,7 @@ class EventHandler
|
|||
static constexpr Int32
|
||||
COMBO_SIZE = 16,
|
||||
EVENTS_PER_COMBO = 8,
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
PNG_SIZE = 3,
|
||||
#else
|
||||
PNG_SIZE = 0,
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include "PropsSet.hxx"
|
||||
#include "EventHandler.hxx"
|
||||
#include "PNGLibrary.hxx"
|
||||
#include "JPGLibrary.hxx"
|
||||
#include "Console.hxx"
|
||||
#include "Random.hxx"
|
||||
#include "StateManager.hxx"
|
||||
|
@ -90,8 +91,8 @@ OSystem::OSystem()
|
|||
#ifdef CHEATCODE_SUPPORT
|
||||
myFeatures += "Cheats ";
|
||||
#endif
|
||||
#ifdef PNG_SUPPORT
|
||||
myFeatures += "PNG ";
|
||||
#ifdef IMAGE_SUPPORT
|
||||
myFeatures += "Images ";
|
||||
#endif
|
||||
#ifdef ZIP_SUPPORT
|
||||
myFeatures += "ZIP";
|
||||
|
@ -196,9 +197,11 @@ bool OSystem::initialize(const Settings::Options& options)
|
|||
myHighScoresManager->setRepository(getHighscoreRepository());
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
// Create PNG handler
|
||||
myPNGLib = make_unique<PNGLibrary>(*this);
|
||||
// Create JPG handler
|
||||
myJPGLib = make_unique<JPGLibrary>(*this);
|
||||
#endif
|
||||
|
||||
// Detect serial port for AtariVox-USB
|
||||
|
@ -289,7 +292,7 @@ void OSystem::setConfigPaths()
|
|||
buildDirIfRequired(myCfgDir, myBaseDir, "cfg");
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
const string& ssSaveDir = mySettings->getString("snapsavedir");
|
||||
if(ssSaveDir == EmptyString)
|
||||
mySnapshotSaveDir = userDir();
|
||||
|
|
|
@ -46,8 +46,9 @@ class AudioSettings;
|
|||
class TimeMachine;
|
||||
class VideoAudioDialog;
|
||||
#endif
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
class PNGLibrary;
|
||||
class JPGLibrary;
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
|
@ -249,14 +250,21 @@ class OSystem
|
|||
TimeMachine& timeMachine() const { return *myTimeMachine; }
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
/**
|
||||
Get the PNG handler of the system.
|
||||
|
||||
@return The PNGlib object
|
||||
*/
|
||||
PNGLibrary& png() const { return *myPNGLib; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
Get the JPG handler of the system.
|
||||
|
||||
@return The JPGlib object
|
||||
*/
|
||||
JPGLibrary& jpg() const { return *myJPGLib; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
Set all config file paths for the OSystem.
|
||||
|
@ -293,7 +301,7 @@ class OSystem
|
|||
const FSNode& cfgDir() const { return myCfgDir; }
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
/**
|
||||
Return the full/complete path name for saving and loading
|
||||
PNG snapshots.
|
||||
|
@ -561,9 +569,12 @@ class OSystem
|
|||
unique_ptr<TimeMachine> myTimeMachine;
|
||||
#endif
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
// PNG object responsible for loading/saving PNG images
|
||||
unique_ptr<PNGLibrary> myPNGLib;
|
||||
|
||||
// JPG object responsible for loading/saving JPG images
|
||||
unique_ptr<JPGLibrary> myJPGLib;
|
||||
#endif
|
||||
|
||||
// Pointer to the StateManager object
|
||||
|
|
|
@ -601,7 +601,7 @@ void TIASurface::render(bool shade)
|
|||
if(mySaveSnapFlag)
|
||||
{
|
||||
mySaveSnapFlag = false;
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
myOSystem.png().takeSnapshot();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "Dialog.hxx"
|
||||
#include "FBSurface.hxx"
|
||||
#include "Font.hxx"
|
||||
#include "JPGLibrary.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "PNGLibrary.hxx"
|
||||
#include "Props.hxx"
|
||||
|
@ -59,7 +60,7 @@ void RomImageWidget::clearProperties()
|
|||
{
|
||||
myHaveProperties = mySurfaceIsValid = false;
|
||||
if(mySurface)
|
||||
mySurface->setVisible(mySurfaceIsValid);
|
||||
mySurface->setVisible(false);
|
||||
|
||||
// Decide whether the information should be shown immediately
|
||||
if(instance().eventHandler().state() == EventHandlerState::LAUNCHER)
|
||||
|
@ -84,6 +85,7 @@ void RomImageWidget::parseProperties(const FSNode& node, bool full)
|
|||
// Create navigation surface
|
||||
myNavSurface = instance().frameBuffer().allocateSurface(
|
||||
_w, myImageHeight);
|
||||
myNavSurface->setDstRect(Common::Rect(_x, _y, _x + _w, _y + myImageHeight));
|
||||
|
||||
FBSurface::Attributes& attr = myNavSurface->attributes();
|
||||
|
||||
|
@ -103,77 +105,73 @@ void RomImageWidget::parseProperties(const FSNode& node, bool full)
|
|||
|
||||
dialog().addRenderCallback([this]() {
|
||||
if(mySurfaceIsValid)
|
||||
{
|
||||
mySurface->render();
|
||||
if(isHighlighted())
|
||||
myNavSurface->render();
|
||||
}
|
||||
if(isHighlighted())
|
||||
myNavSurface->render();
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
if(!full)
|
||||
{
|
||||
myImageIdx = 0;
|
||||
myImageList.clear();
|
||||
mySurfaceErrorMsg = "";
|
||||
|
||||
// Get a valid filename representing a snapshot file for this rom and load the snapshot
|
||||
const string& path = instance().snapshotLoadDir().getPath();
|
||||
// 1. Try to load first snapshot by property name
|
||||
string fileName = path + myProperties.get(PropType::Cart_Name) + ".png";
|
||||
string fileName = path + myProperties.get(PropType::Cart_Name);// +".png"; // TODO: try jpg
|
||||
|
||||
mySurfaceIsValid = loadPng(fileName);
|
||||
tryImageTypes(fileName);
|
||||
|
||||
loadImage(fileName);
|
||||
if(!mySurfaceIsValid)
|
||||
{
|
||||
// 2. If none exists, try to load first snapshot by ROM file name
|
||||
fileName = path + node.getNameWithExt("png");
|
||||
mySurfaceIsValid = loadPng(fileName);
|
||||
fileName = path + node.getNameWithExt("png"); // TODO: try jpg
|
||||
loadImage(fileName);
|
||||
}
|
||||
if(mySurfaceIsValid)
|
||||
myImageList.emplace_back(fileName);
|
||||
else
|
||||
// 3. If no ROM snapshots exist, try to load a default snapshot
|
||||
mySurfaceIsValid = loadPng(path + "default_snapshot.png");
|
||||
loadImage(path + "default_snapshot.png"); // TODO: try jpg???
|
||||
}
|
||||
else
|
||||
{
|
||||
const string& oldFileName = myImageList.size() ? myImageList[0].getPath() : "";
|
||||
const string& oldFileName = myImageList.size() ? myImageList[0].getPath() : EmptyString;
|
||||
|
||||
// Try to find all snapshots by property and ROM file name
|
||||
myImageList.clear();
|
||||
getImageList(myProperties.get(PropType::Cart_Name), node.getNameWithExt());
|
||||
|
||||
// The first file found before must not be the first file now, if files by
|
||||
// property *and* ROM name are found
|
||||
// property *and* ROM name are found (TODO: fix that!)
|
||||
if(myImageList.size() && myImageList[0].getPath() != oldFileName)
|
||||
{
|
||||
mySurfaceErrorMsg = "";
|
||||
mySurfaceIsValid = loadPng(myImageList[0].getPath());
|
||||
}
|
||||
loadImage(myImageList[0].getPath());
|
||||
}
|
||||
#else
|
||||
mySurfaceIsValid = false;
|
||||
mySurfaceErrorMsg = "PNG image loading not supported";
|
||||
setDirty();
|
||||
#endif
|
||||
if(mySurface)
|
||||
mySurface->setVisible(mySurfaceIsValid);
|
||||
|
||||
setDirty();
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomImageWidget::changeImage(int direction)
|
||||
{
|
||||
#ifdef IMAGE_SUPPORT
|
||||
if(direction == -1 && myImageIdx)
|
||||
return loadPng(myImageList[--myImageIdx].getPath());
|
||||
return loadImage(myImageList[--myImageIdx].getPath());
|
||||
else if(direction == 1 && myImageIdx < myImageList.size() - 1)
|
||||
return loadPng(myImageList[++myImageIdx].getPath());
|
||||
|
||||
return loadImage(myImageList[++myImageIdx].getPath());
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomImageWidget::getImageList(const string& propName, const string& romName)
|
||||
{
|
||||
|
@ -181,7 +179,7 @@ bool RomImageWidget::getImageList(const string& propName, const string& romName)
|
|||
const string rgxPropName = std::regex_replace(propName, symbols, R"(\$&)");
|
||||
const string rgxRomName = std::regex_replace(romName, symbols, R"(\$&)");
|
||||
// Look for <name.png> or <name_#.png> (# is a number)
|
||||
const std::regex rgx("^(" + rgxPropName + "|" + rgxRomName + ")(_\\d+){0,1}\\.png$");
|
||||
const std::regex rgx("^(" + rgxPropName + "|" + rgxRomName + ")(_\\d+){0,1}\\.(png|jpg)$");
|
||||
|
||||
FSNode::NameFilter filter = ([&](const FSNode& node)
|
||||
{
|
||||
|
@ -197,20 +195,60 @@ bool RomImageWidget::getImageList(const string& propName, const string& romName)
|
|||
// the end of the list
|
||||
std::sort(myImageList.begin(), myImageList.end(),
|
||||
[](const FSNode& node1, const FSNode& node2)
|
||||
{
|
||||
return BSPF::compareIgnoreCase(node1.getNameWithExt(), node2.getNameWithExt()) < 0;
|
||||
{
|
||||
int compare = BSPF::compareIgnoreCase(node1.getNameWithExt(), node2.getNameWithExt());
|
||||
return
|
||||
compare < 0 ||
|
||||
(compare == 0 &&
|
||||
node1.getName().substr(node1.getName().find_last_of('.') + 1) >
|
||||
node2.getName().substr(node2.getName().find_last_of('.') + 1)); // PNGs first!
|
||||
}
|
||||
);
|
||||
return myImageList.size() > 0;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomImageWidget::tryImageTypes(string& fileName)
|
||||
{
|
||||
if(loadImage(fileName + ".png"))
|
||||
{
|
||||
fileName += ".png";
|
||||
return true;
|
||||
}
|
||||
if(loadImage(fileName + ".jpg"))
|
||||
{
|
||||
fileName += ".jpg";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomImageWidget::loadImage(const string& fileName)
|
||||
{
|
||||
mySurfaceErrorMsg.clear();
|
||||
|
||||
const string::size_type idx = fileName.find_last_of('.');
|
||||
|
||||
if(idx != string::npos && fileName.substr(idx + 1) == "png")
|
||||
mySurfaceIsValid = loadPng(fileName);
|
||||
else
|
||||
mySurfaceIsValid = loadJpg(fileName);
|
||||
|
||||
if(mySurface)
|
||||
mySurface->setVisible(mySurfaceIsValid);
|
||||
|
||||
setDirty();
|
||||
return mySurfaceIsValid;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomImageWidget::loadPng(const string& fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
VariantList comments;
|
||||
instance().png().loadImage(fileName, *mySurface, comments);
|
||||
instance().png().loadImage(fileName, *mySurface, comments);
|
||||
|
||||
// Scale surface to available image area
|
||||
const Common::Rect& src = mySurface->srcRect();
|
||||
|
@ -219,7 +257,7 @@ bool RomImageWidget::loadPng(const string& fileName)
|
|||
mySurface->setDstSize(static_cast<uInt32>(src.w() * scale), static_cast<uInt32>(src.h() * scale));
|
||||
|
||||
// Retrieve label for loaded image
|
||||
myLabel = "";
|
||||
myLabel.clear();
|
||||
for(auto comment = comments.begin(); comment != comments.end(); ++comment)
|
||||
{
|
||||
if(comment->first == "Title")
|
||||
|
@ -231,8 +269,6 @@ bool RomImageWidget::loadPng(const string& fileName)
|
|||
&& comment->second.toString().find("Stella") == 0)
|
||||
myLabel = "Snapshot"; // default for Stella snapshots with missing "Title" comment
|
||||
}
|
||||
|
||||
setDirty();
|
||||
return true;
|
||||
}
|
||||
catch(const runtime_error& e)
|
||||
|
@ -242,6 +278,25 @@ bool RomImageWidget::loadPng(const string& fileName)
|
|||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
bool RomImageWidget::loadJpg(const string& fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
VariantList comments;
|
||||
instance().jpg().loadImage(fileName, *mySurface, comments);
|
||||
|
||||
myLabel.clear();
|
||||
return true;
|
||||
}
|
||||
catch(const runtime_error& e)
|
||||
{
|
||||
mySurfaceErrorMsg = e.what();
|
||||
}
|
||||
//mySurfaceErrorMsg = "JPG image loading not supported";
|
||||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomImageWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
|
||||
{
|
||||
|
@ -252,7 +307,7 @@ void RomImageWidget::handleMouseUp(int x, int y, MouseButton b, int clickCount)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void RomImageWidget::handleMouseMoved(int x, int y)
|
||||
{
|
||||
if(x < _w / 2 != myMouseLeft)
|
||||
if((x < _w / 2) != myMouseLeft)
|
||||
setDirty();
|
||||
myMouseLeft = x < _w / 2;
|
||||
}
|
||||
|
@ -285,51 +340,50 @@ void RomImageWidget::drawWidget(bool hilite)
|
|||
const Common::Rect& s_dst = s.dstRect();
|
||||
mySurface->setDstPos(x + s_dst.x(), y + s_dst.y());
|
||||
|
||||
// Draw the image label and counter
|
||||
ostringstream buf;
|
||||
buf << myImageIdx + 1 << "/" << myImageList.size();
|
||||
const int yText = _y + myImageHeight + _font.getFontHeight() / 8;
|
||||
const int wText = _font.getStringWidth(buf.str());
|
||||
|
||||
if(myLabel.length())
|
||||
s.drawString(_font, myLabel, _x, yText, _w - wText - _font.getMaxCharWidth() * 2, _textcolor);
|
||||
if(myImageList.size())
|
||||
s.drawString(_font, buf.str(), _x + _w - wText, yText, wText, _textcolor);
|
||||
|
||||
// Draw the navigation arrows
|
||||
myNavSurface->invalidate();
|
||||
if(isHighlighted() &&
|
||||
((myMouseLeft && myImageIdx) || (!myMouseLeft && myImageIdx < myImageList.size() - 1)))
|
||||
{
|
||||
const int w = _w / 64;
|
||||
const int w2 = 1; // w / 2;
|
||||
const int ax = myMouseLeft ? _w / 12 - w / 2 : _w - _w / 12 - w / 2;
|
||||
const int ay = myImageHeight >> 1;
|
||||
const int dx = (_w / 32) * (myMouseLeft ? 1 : -1);
|
||||
const int dy = myImageHeight / 16;
|
||||
|
||||
for(int i = 0; i < w; ++i)
|
||||
{
|
||||
myNavSurface->line(ax + dx + i + w2, ay - dy, ax + i + w2, ay, kBGColor);
|
||||
myNavSurface->line(ax + dx + i + w2, ay + dy, ax + i + w2, ay, kBGColor);
|
||||
myNavSurface->line(ax + dx + i, ay - dy + w2, ax + i, ay + w2, kBGColor);
|
||||
myNavSurface->line(ax + dx + i, ay + dy + w2, ax + i, ay + w2, kBGColor);
|
||||
myNavSurface->line(ax + dx + i + w2, ay - dy + w2, ax + i + w2, ay + w2, kBGColor);
|
||||
myNavSurface->line(ax + dx + i + w2, ay + dy + w2, ax + i + w2, ay + w2, kBGColor);
|
||||
}
|
||||
for(int i = 0; i < w; ++i)
|
||||
{
|
||||
myNavSurface->line(ax + dx + i, ay - dy, ax + i, ay, kColorInfo);
|
||||
myNavSurface->line(ax + dx + i, ay + dy, ax + i, ay, kColorInfo);
|
||||
}
|
||||
myNavSurface->setDstRect(mySurface->dstRect());
|
||||
}
|
||||
}
|
||||
else if(mySurfaceErrorMsg != "")
|
||||
else if(!mySurfaceErrorMsg.empty())
|
||||
{
|
||||
const uInt32 x = _x + ((_w - _font.getStringWidth(mySurfaceErrorMsg)) >> 1);
|
||||
const uInt32 y = _y + ((yoff - _font.getLineHeight()) >> 1);
|
||||
s.drawString(_font, mySurfaceErrorMsg, x, y, _w - 10, _textcolor);
|
||||
}
|
||||
// Draw the image label and counter
|
||||
ostringstream buf;
|
||||
buf << myImageIdx + 1 << "/" << myImageList.size();
|
||||
const int yText = _y + myImageHeight + _font.getFontHeight() / 8;
|
||||
const int wText = _font.getStringWidth(buf.str());
|
||||
|
||||
if(myLabel.length())
|
||||
s.drawString(_font, myLabel, _x, yText, _w - wText - _font.getMaxCharWidth() * 2, _textcolor);
|
||||
if(myImageList.size())
|
||||
s.drawString(_font, buf.str(), _x + _w - wText, yText, wText, _textcolor);
|
||||
|
||||
// Draw the navigation arrows
|
||||
myNavSurface->invalidate();
|
||||
if(isHighlighted() &&
|
||||
((myMouseLeft && myImageIdx) || (!myMouseLeft && myImageIdx < myImageList.size() - 1)))
|
||||
{
|
||||
const int w = _w / 64;
|
||||
const int w2 = 1; // w / 2;
|
||||
const int ax = myMouseLeft ? _w / 12 - w / 2 : _w - _w / 12 - w / 2;
|
||||
const int ay = myImageHeight >> 1;
|
||||
const int dx = (_w / 32) * (myMouseLeft ? 1 : -1);
|
||||
const int dy = myImageHeight / 16;
|
||||
|
||||
for(int i = 0; i < w; ++i)
|
||||
{
|
||||
myNavSurface->line(ax + dx + i + w2, ay - dy, ax + i + w2, ay, kBGColor);
|
||||
myNavSurface->line(ax + dx + i + w2, ay + dy, ax + i + w2, ay, kBGColor);
|
||||
myNavSurface->line(ax + dx + i, ay - dy + w2, ax + i, ay + w2, kBGColor);
|
||||
myNavSurface->line(ax + dx + i, ay + dy + w2, ax + i, ay + w2, kBGColor);
|
||||
myNavSurface->line(ax + dx + i + w2, ay - dy + w2, ax + i + w2, ay + w2, kBGColor);
|
||||
myNavSurface->line(ax + dx + i + w2, ay + dy + w2, ax + i + w2, ay + w2, kBGColor);
|
||||
}
|
||||
for(int i = 0; i < w; ++i)
|
||||
{
|
||||
myNavSurface->line(ax + dx + i, ay - dy, ax + i, ay, kColorInfo);
|
||||
myNavSurface->line(ax + dx + i, ay + dy, ax + i, ay, kColorInfo);
|
||||
}
|
||||
}
|
||||
clearDirty();
|
||||
}
|
||||
|
|
|
@ -42,16 +42,19 @@ class RomImageWidget : public Widget, public CommandSender
|
|||
|
||||
protected:
|
||||
void drawWidget(bool hilite) override;
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
||||
void handleMouseMoved(int x, int y) override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void parseProperties(const FSNode& node, bool full = true);
|
||||
#ifdef PNG_SUPPORT
|
||||
#ifdef IMAGE_SUPPORT
|
||||
bool getImageList(const string& propName, const string& romName);
|
||||
bool tryImageTypes(string& fileName);
|
||||
bool loadImage(const string& fileName);
|
||||
bool loadPng(const string& fileName);
|
||||
bool loadJpg(const string& fileName);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
|
@ -3543,7 +3543,7 @@
|
|||
DEBUGGER_SUPPORT,
|
||||
HTTP_LIB_SUPPORT,
|
||||
JOYSTICK_SUPPORT,
|
||||
PNG_SUPPORT,
|
||||
IMAGE_SUPPORT,
|
||||
ZIP_SUPPORT,
|
||||
SOUND_SUPPORT,
|
||||
WINDOWED_SUPPORT,
|
||||
|
@ -3606,7 +3606,7 @@
|
|||
DEBUGGER_SUPPORT,
|
||||
HTTP_LIB_SUPPORT,
|
||||
JOYSTICK_SUPPORT,
|
||||
PNG_SUPPORT,
|
||||
IMAGE_SUPPORT,
|
||||
ZIP_SUPPORT,
|
||||
SOUND_SUPPORT,
|
||||
WINDOWED_SUPPORT,
|
||||
|
|
|
@ -0,0 +1,916 @@
|
|||
// NanoJPEG -- KeyJ's Tiny Baseline JPEG Decoder
|
||||
// version 1.3.5 (2016-11-14)
|
||||
// Copyright (c) 2009-2016 Martin J. Fiedler <martin.fiedler@gmx.net>
|
||||
// published under the terms of the MIT license
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to
|
||||
// deal in the Software without restriction, including without limitation the
|
||||
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
// sell copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// DOCUMENTATION SECTION //
|
||||
// read this if you want to know what this is all about //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// INTRODUCTION
|
||||
// ============
|
||||
//
|
||||
// This is a minimal decoder for baseline JPEG images. It accepts memory dumps
|
||||
// of JPEG files as input and generates either 8-bit grayscale or packed 24-bit
|
||||
// RGB images as output. It does not parse JFIF or Exif headers; all JPEG files
|
||||
// are assumed to be either grayscale or YCbCr. CMYK or other color spaces are
|
||||
// not supported. All YCbCr subsampling schemes with power-of-two ratios are
|
||||
// supported, as are restart intervals. Progressive or lossless JPEG is not
|
||||
// supported.
|
||||
// Summed up, NanoJPEG should be able to decode all images from digital cameras
|
||||
// and most common forms of other non-progressive JPEG images.
|
||||
// The decoder is not optimized for speed, it's optimized for simplicity and
|
||||
// small code. Image quality should be at a reasonable level. A bicubic chroma
|
||||
// upsampling filter ensures that subsampled YCbCr images are rendered in
|
||||
// decent quality. The decoder is not meant to deal with broken JPEG files in
|
||||
// a graceful manner; if anything is wrong with the bitstream, decoding will
|
||||
// simply fail.
|
||||
// The code should work with every modern C compiler without problems and
|
||||
// should not emit any warnings. It uses only (at least) 32-bit integer
|
||||
// arithmetic and is supposed to be endianness independent and 64-bit clean.
|
||||
// However, it is not thread-safe.
|
||||
|
||||
|
||||
// COMPILE-TIME CONFIGURATION
|
||||
// ==========================
|
||||
//
|
||||
// The following aspects of NanoJPEG can be controlled with preprocessor
|
||||
// defines:
|
||||
//
|
||||
// _NJ_EXAMPLE_PROGRAM = Compile a main() function with an example
|
||||
// program.
|
||||
// _NJ_INCLUDE_HEADER_ONLY = Don't compile anything, just act as a header
|
||||
// file for NanoJPEG. Example:
|
||||
// #define _NJ_INCLUDE_HEADER_ONLY
|
||||
// #include "nanojpeg.c"
|
||||
// int main(void) {
|
||||
// njInit();
|
||||
// // your code here
|
||||
// njDone();
|
||||
// }
|
||||
// NJ_USE_LIBC=1 = Use the malloc(), free(), memset() and memcpy()
|
||||
// functions from the standard C library (default).
|
||||
// NJ_USE_LIBC=0 = Don't use the standard C library. In this mode,
|
||||
// external functions njAlloc(), njFreeMem(),
|
||||
// njFillMem() and njCopyMem() need to be defined
|
||||
// and implemented somewhere.
|
||||
// NJ_USE_WIN32=0 = Normal mode (default).
|
||||
// NJ_USE_WIN32=1 = If compiling with MSVC for Win32 and
|
||||
// NJ_USE_LIBC=0, NanoJPEG will use its own
|
||||
// implementations of the required C library
|
||||
// functions (default if compiling with MSVC and
|
||||
// NJ_USE_LIBC=0).
|
||||
// NJ_CHROMA_FILTER=1 = Use the bicubic chroma upsampling filter
|
||||
// (default).
|
||||
// NJ_CHROMA_FILTER=0 = Use simple pixel repetition for chroma upsampling
|
||||
// (bad quality, but faster and less code).
|
||||
|
||||
|
||||
// API
|
||||
// ===
|
||||
//
|
||||
// For API documentation, read the "header section" below.
|
||||
|
||||
|
||||
// EXAMPLE
|
||||
// =======
|
||||
//
|
||||
// A few pages below, you can find an example program that uses NanoJPEG to
|
||||
// convert JPEG files into PGM or PPM. To compile it, use something like
|
||||
// gcc -O3 -D_NJ_EXAMPLE_PROGRAM -o nanojpeg nanojpeg.c
|
||||
// You may also add -std=c99 -Wall -Wextra -pedantic -Werror, if you want :)
|
||||
// The only thing you might need is -Wno-shift-negative-value, because this
|
||||
// code relies on the target machine using two's complement arithmetic, but
|
||||
// the C standard does not, even though *any* practically useful machine
|
||||
// nowadays uses two's complement.
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// HEADER SECTION //
|
||||
// copy and pase this into nanojpeg.h if you want //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _NANOJPEG_H
|
||||
#define _NANOJPEG_H
|
||||
|
||||
// nj_result_t: Result codes for njDecode().
|
||||
typedef enum _nj_result {
|
||||
NJ_OK = 0, // no error, decoding successful
|
||||
NJ_NO_JPEG, // not a JPEG file
|
||||
NJ_UNSUPPORTED, // unsupported format
|
||||
NJ_OUT_OF_MEM, // out of memory
|
||||
NJ_INTERNAL_ERR, // internal error
|
||||
NJ_SYNTAX_ERROR, // syntax error
|
||||
__NJ_FINISHED, // used internally, will never be reported
|
||||
} nj_result_t;
|
||||
|
||||
// njInit: Initialize NanoJPEG.
|
||||
// For safety reasons, this should be called at least one time before using
|
||||
// using any of the other NanoJPEG functions.
|
||||
void njInit(void);
|
||||
|
||||
// njDecode: Decode a JPEG image.
|
||||
// Decodes a memory dump of a JPEG file into internal buffers.
|
||||
// Parameters:
|
||||
// jpeg = The pointer to the memory dump.
|
||||
// size = The size of the JPEG file.
|
||||
// Return value: The error code in case of failure, or NJ_OK (zero) on success.
|
||||
nj_result_t njDecode(const void* jpeg, const int size);
|
||||
|
||||
// njGetWidth: Return the width (in pixels) of the most recently decoded
|
||||
// image. If njDecode() failed, the result of njGetWidth() is undefined.
|
||||
int njGetWidth(void);
|
||||
|
||||
// njGetHeight: Return the height (in pixels) of the most recently decoded
|
||||
// image. If njDecode() failed, the result of njGetHeight() is undefined.
|
||||
int njGetHeight(void);
|
||||
|
||||
// njIsColor: Return 1 if the most recently decoded image is a color image
|
||||
// (RGB) or 0 if it is a grayscale image. If njDecode() failed, the result
|
||||
// of njGetWidth() is undefined.
|
||||
int njIsColor(void);
|
||||
|
||||
// njGetImage: Returns the decoded image data.
|
||||
// Returns a pointer to the most recently image. The memory layout it byte-
|
||||
// oriented, top-down, without any padding between lines. Pixels of color
|
||||
// images will be stored as three consecutive bytes for the red, green and
|
||||
// blue channels. This data format is thus compatible with the PGM or PPM
|
||||
// file formats and the OpenGL texture formats GL_LUMINANCE8 or GL_RGB8.
|
||||
// If njDecode() failed, the result of njGetImage() is undefined.
|
||||
unsigned char* njGetImage(void);
|
||||
|
||||
// njGetImageSize: Returns the size (in bytes) of the image data returned
|
||||
// by njGetImage(). If njDecode() failed, the result of njGetImageSize() is
|
||||
// undefined.
|
||||
int njGetImageSize(void);
|
||||
|
||||
// njDone: Uninitialize NanoJPEG.
|
||||
// Resets NanoJPEG's internal state and frees all memory that has been
|
||||
// allocated at run-time by NanoJPEG. It is still possible to decode another
|
||||
// image after a njDone() call.
|
||||
void njDone(void);
|
||||
|
||||
#endif//_NANOJPEG_H
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CONFIGURATION SECTION //
|
||||
// adjust the default settings for the NJ_ defines here //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef NJ_USE_LIBC
|
||||
#define NJ_USE_LIBC 1
|
||||
#endif
|
||||
|
||||
#ifndef NJ_USE_WIN32
|
||||
#ifdef _MSC_VER
|
||||
#define NJ_USE_WIN32 (!NJ_USE_LIBC)
|
||||
#else
|
||||
#define NJ_USE_WIN32 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NJ_CHROMA_FILTER
|
||||
#define NJ_CHROMA_FILTER 1
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EXAMPLE PROGRAM //
|
||||
// just define _NJ_EXAMPLE_PROGRAM to compile this (requires NJ_USE_LIBC) //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _NJ_EXAMPLE_PROGRAM
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int size;
|
||||
char *buf;
|
||||
FILE *f;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: %s <input.jpg> [<output.ppm>]\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
f = fopen(argv[1], "rb");
|
||||
if (!f) {
|
||||
printf("Error opening the input file.\n");
|
||||
return 1;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = (int) ftell(f);
|
||||
buf = (char*) malloc(size);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
size = (int) fread(buf, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
njInit();
|
||||
if (njDecode(buf, size)) {
|
||||
free((void*)buf);
|
||||
printf("Error decoding the input file.\n");
|
||||
return 1;
|
||||
}
|
||||
free((void*)buf);
|
||||
|
||||
f = fopen((argc > 2) ? argv[2] : (njIsColor() ? "nanojpeg_out.ppm" : "nanojpeg_out.pgm"), "wb");
|
||||
if (!f) {
|
||||
printf("Error opening the output file.\n");
|
||||
return 1;
|
||||
}
|
||||
fprintf(f, "P%d\n%d %d\n255\n", njIsColor() ? 6 : 5, njGetWidth(), njGetHeight());
|
||||
fwrite(njGetImage(), 1, njGetImageSize(), f);
|
||||
fclose(f);
|
||||
njDone();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// IMPLEMENTATION SECTION //
|
||||
// you may stop reading here //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _NJ_INCLUDE_HEADER_ONLY
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define NJ_INLINE static __inline
|
||||
#define NJ_FORCE_INLINE static __forceinline
|
||||
#else
|
||||
#define NJ_INLINE static inline
|
||||
#define NJ_FORCE_INLINE static inline
|
||||
#endif
|
||||
|
||||
#if NJ_USE_LIBC
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define njAllocMem malloc
|
||||
#define njFreeMem free
|
||||
#define njFillMem memset
|
||||
#define njCopyMem memcpy
|
||||
#elif NJ_USE_WIN32
|
||||
#include <windows.h>
|
||||
#define njAllocMem(size) ((void*) LocalAlloc(LMEM_FIXED, (SIZE_T)(size)))
|
||||
#define njFreeMem(block) ((void) LocalFree((HLOCAL) block))
|
||||
NJ_INLINE void njFillMem(void* block, unsigned char value, int count) { __asm {
|
||||
mov edi, block
|
||||
mov al, value
|
||||
mov ecx, count
|
||||
rep stosb
|
||||
} }
|
||||
NJ_INLINE void njCopyMem(void* dest, const void* src, int count) { __asm {
|
||||
mov edi, dest
|
||||
mov esi, src
|
||||
mov ecx, count
|
||||
rep movsb
|
||||
} }
|
||||
#else
|
||||
extern void* njAllocMem(int size);
|
||||
extern void njFreeMem(void* block);
|
||||
extern void njFillMem(void* block, unsigned char byte, int size);
|
||||
extern void njCopyMem(void* dest, const void* src, int size);
|
||||
#endif
|
||||
|
||||
typedef struct _nj_code {
|
||||
unsigned char bits, code;
|
||||
} nj_vlc_code_t;
|
||||
|
||||
typedef struct _nj_cmp {
|
||||
int cid;
|
||||
int ssx, ssy;
|
||||
int width, height;
|
||||
int stride;
|
||||
int qtsel;
|
||||
int actabsel, dctabsel;
|
||||
int dcpred;
|
||||
unsigned char *pixels;
|
||||
} nj_component_t;
|
||||
|
||||
typedef struct _nj_ctx {
|
||||
nj_result_t error;
|
||||
const unsigned char *pos;
|
||||
int size;
|
||||
int length;
|
||||
int width, height;
|
||||
int mbwidth, mbheight;
|
||||
int mbsizex, mbsizey;
|
||||
int ncomp;
|
||||
nj_component_t comp[3];
|
||||
int qtused, qtavail;
|
||||
unsigned char qtab[4][64];
|
||||
nj_vlc_code_t vlctab[4][65536];
|
||||
int buf, bufbits;
|
||||
int block[64];
|
||||
int rstinterval;
|
||||
unsigned char *rgb;
|
||||
} nj_context_t;
|
||||
|
||||
static nj_context_t nj;
|
||||
|
||||
static const char njZZ[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18,
|
||||
11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35,
|
||||
42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45,
|
||||
38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 };
|
||||
|
||||
NJ_FORCE_INLINE unsigned char njClip(const int x) {
|
||||
return (x < 0) ? 0 : ((x > 0xFF) ? 0xFF : (unsigned char) x);
|
||||
}
|
||||
|
||||
#define W1 2841
|
||||
#define W2 2676
|
||||
#define W3 2408
|
||||
#define W5 1609
|
||||
#define W6 1108
|
||||
#define W7 565
|
||||
|
||||
NJ_INLINE void njRowIDCT(int* blk) {
|
||||
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
|
||||
if (!((x1 = blk[4] << 11)
|
||||
| (x2 = blk[6])
|
||||
| (x3 = blk[2])
|
||||
| (x4 = blk[1])
|
||||
| (x5 = blk[7])
|
||||
| (x6 = blk[5])
|
||||
| (x7 = blk[3])))
|
||||
{
|
||||
blk[0] = blk[1] = blk[2] = blk[3] = blk[4] = blk[5] = blk[6] = blk[7] = blk[0] << 3;
|
||||
return;
|
||||
}
|
||||
x0 = (blk[0] << 11) + 128;
|
||||
x8 = W7 * (x4 + x5);
|
||||
x4 = x8 + (W1 - W7) * x4;
|
||||
x5 = x8 - (W1 + W7) * x5;
|
||||
x8 = W3 * (x6 + x7);
|
||||
x6 = x8 - (W3 - W5) * x6;
|
||||
x7 = x8 - (W3 + W5) * x7;
|
||||
x8 = x0 + x1;
|
||||
x0 -= x1;
|
||||
x1 = W6 * (x3 + x2);
|
||||
x2 = x1 - (W2 + W6) * x2;
|
||||
x3 = x1 + (W2 - W6) * x3;
|
||||
x1 = x4 + x6;
|
||||
x4 -= x6;
|
||||
x6 = x5 + x7;
|
||||
x5 -= x7;
|
||||
x7 = x8 + x3;
|
||||
x8 -= x3;
|
||||
x3 = x0 + x2;
|
||||
x0 -= x2;
|
||||
x2 = (181 * (x4 + x5) + 128) >> 8;
|
||||
x4 = (181 * (x4 - x5) + 128) >> 8;
|
||||
blk[0] = (x7 + x1) >> 8;
|
||||
blk[1] = (x3 + x2) >> 8;
|
||||
blk[2] = (x0 + x4) >> 8;
|
||||
blk[3] = (x8 + x6) >> 8;
|
||||
blk[4] = (x8 - x6) >> 8;
|
||||
blk[5] = (x0 - x4) >> 8;
|
||||
blk[6] = (x3 - x2) >> 8;
|
||||
blk[7] = (x7 - x1) >> 8;
|
||||
}
|
||||
|
||||
NJ_INLINE void njColIDCT(const int* blk, unsigned char *out, int stride) {
|
||||
int x0, x1, x2, x3, x4, x5, x6, x7, x8;
|
||||
if (!((x1 = blk[8*4] << 8)
|
||||
| (x2 = blk[8*6])
|
||||
| (x3 = blk[8*2])
|
||||
| (x4 = blk[8*1])
|
||||
| (x5 = blk[8*7])
|
||||
| (x6 = blk[8*5])
|
||||
| (x7 = blk[8*3])))
|
||||
{
|
||||
x1 = njClip(((blk[0] + 32) >> 6) + 128);
|
||||
for (x0 = 8; x0; --x0) {
|
||||
*out = (unsigned char) x1;
|
||||
out += stride;
|
||||
}
|
||||
return;
|
||||
}
|
||||
x0 = (blk[0] << 8) + 8192;
|
||||
x8 = W7 * (x4 + x5) + 4;
|
||||
x4 = (x8 + (W1 - W7) * x4) >> 3;
|
||||
x5 = (x8 - (W1 + W7) * x5) >> 3;
|
||||
x8 = W3 * (x6 + x7) + 4;
|
||||
x6 = (x8 - (W3 - W5) * x6) >> 3;
|
||||
x7 = (x8 - (W3 + W5) * x7) >> 3;
|
||||
x8 = x0 + x1;
|
||||
x0 -= x1;
|
||||
x1 = W6 * (x3 + x2) + 4;
|
||||
x2 = (x1 - (W2 + W6) * x2) >> 3;
|
||||
x3 = (x1 + (W2 - W6) * x3) >> 3;
|
||||
x1 = x4 + x6;
|
||||
x4 -= x6;
|
||||
x6 = x5 + x7;
|
||||
x5 -= x7;
|
||||
x7 = x8 + x3;
|
||||
x8 -= x3;
|
||||
x3 = x0 + x2;
|
||||
x0 -= x2;
|
||||
x2 = (181 * (x4 + x5) + 128) >> 8;
|
||||
x4 = (181 * (x4 - x5) + 128) >> 8;
|
||||
*out = njClip(((x7 + x1) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x3 + x2) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x0 + x4) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x8 + x6) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x8 - x6) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x0 - x4) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x3 - x2) >> 14) + 128); out += stride;
|
||||
*out = njClip(((x7 - x1) >> 14) + 128);
|
||||
}
|
||||
|
||||
#define njThrow(e) do { nj.error = e; return; } while (0)
|
||||
#define njCheckError() do { if (nj.error) return; } while (0)
|
||||
|
||||
static int njShowBits(int bits) {
|
||||
unsigned char newbyte;
|
||||
if (!bits) return 0;
|
||||
while (nj.bufbits < bits) {
|
||||
if (nj.size <= 0) {
|
||||
nj.buf = (nj.buf << 8) | 0xFF;
|
||||
nj.bufbits += 8;
|
||||
continue;
|
||||
}
|
||||
newbyte = *nj.pos++;
|
||||
nj.size--;
|
||||
nj.bufbits += 8;
|
||||
nj.buf = (nj.buf << 8) | newbyte;
|
||||
if (newbyte == 0xFF) {
|
||||
if (nj.size) {
|
||||
unsigned char marker = *nj.pos++;
|
||||
nj.size--;
|
||||
switch (marker) {
|
||||
case 0x00:
|
||||
case 0xFF:
|
||||
break;
|
||||
case 0xD9: nj.size = 0; break;
|
||||
default:
|
||||
if ((marker & 0xF8) != 0xD0)
|
||||
nj.error = NJ_SYNTAX_ERROR;
|
||||
else {
|
||||
nj.buf = (nj.buf << 8) | marker;
|
||||
nj.bufbits += 8;
|
||||
}
|
||||
}
|
||||
} else
|
||||
nj.error = NJ_SYNTAX_ERROR;
|
||||
}
|
||||
}
|
||||
return (nj.buf >> (nj.bufbits - bits)) & ((1 << bits) - 1);
|
||||
}
|
||||
|
||||
NJ_INLINE void njSkipBits(int bits) {
|
||||
if (nj.bufbits < bits)
|
||||
(void) njShowBits(bits);
|
||||
nj.bufbits -= bits;
|
||||
}
|
||||
|
||||
NJ_INLINE int njGetBits(int bits) {
|
||||
int res = njShowBits(bits);
|
||||
njSkipBits(bits);
|
||||
return res;
|
||||
}
|
||||
|
||||
NJ_INLINE void njByteAlign(void) {
|
||||
nj.bufbits &= 0xF8;
|
||||
}
|
||||
|
||||
static void njSkip(int count) {
|
||||
nj.pos += count;
|
||||
nj.size -= count;
|
||||
nj.length -= count;
|
||||
if (nj.size < 0) nj.error = NJ_SYNTAX_ERROR;
|
||||
}
|
||||
|
||||
NJ_INLINE unsigned short njDecode16(const unsigned char *pos) {
|
||||
return (pos[0] << 8) | pos[1];
|
||||
}
|
||||
|
||||
static void njDecodeLength(void) {
|
||||
if (nj.size < 2) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.length = njDecode16(nj.pos);
|
||||
if (nj.length > nj.size) njThrow(NJ_SYNTAX_ERROR);
|
||||
njSkip(2);
|
||||
}
|
||||
|
||||
NJ_INLINE void njSkipMarker(void) {
|
||||
njDecodeLength();
|
||||
njSkip(nj.length);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeSOF(void) {
|
||||
int i, ssxmax = 0, ssymax = 0;
|
||||
nj_component_t* c;
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
if (nj.length < 9) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (nj.pos[0] != 8) njThrow(NJ_UNSUPPORTED);
|
||||
nj.height = njDecode16(nj.pos+1);
|
||||
nj.width = njDecode16(nj.pos+3);
|
||||
if (!nj.width || !nj.height) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.ncomp = nj.pos[5];
|
||||
njSkip(6);
|
||||
switch (nj.ncomp) {
|
||||
case 1:
|
||||
case 3:
|
||||
break;
|
||||
default:
|
||||
njThrow(NJ_UNSUPPORTED);
|
||||
}
|
||||
if (nj.length < (nj.ncomp * 3)) njThrow(NJ_SYNTAX_ERROR);
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
c->cid = nj.pos[0];
|
||||
if (!(c->ssx = nj.pos[1] >> 4)) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (c->ssx & (c->ssx - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
|
||||
if (!(c->ssy = nj.pos[1] & 15)) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (c->ssy & (c->ssy - 1)) njThrow(NJ_UNSUPPORTED); // non-power of two
|
||||
if ((c->qtsel = nj.pos[2]) & 0xFC) njThrow(NJ_SYNTAX_ERROR);
|
||||
njSkip(3);
|
||||
nj.qtused |= 1 << c->qtsel;
|
||||
if (c->ssx > ssxmax) ssxmax = c->ssx;
|
||||
if (c->ssy > ssymax) ssymax = c->ssy;
|
||||
}
|
||||
if (nj.ncomp == 1) {
|
||||
c = nj.comp;
|
||||
c->ssx = c->ssy = ssxmax = ssymax = 1;
|
||||
}
|
||||
nj.mbsizex = ssxmax << 3;
|
||||
nj.mbsizey = ssymax << 3;
|
||||
nj.mbwidth = (nj.width + nj.mbsizex - 1) / nj.mbsizex;
|
||||
nj.mbheight = (nj.height + nj.mbsizey - 1) / nj.mbsizey;
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
c->width = (nj.width * c->ssx + ssxmax - 1) / ssxmax;
|
||||
c->height = (nj.height * c->ssy + ssymax - 1) / ssymax;
|
||||
c->stride = nj.mbwidth * c->ssx << 3;
|
||||
if (((c->width < 3) && (c->ssx != ssxmax)) || ((c->height < 3) && (c->ssy != ssymax))) njThrow(NJ_UNSUPPORTED);
|
||||
if (!(c->pixels = (unsigned char*) njAllocMem(c->stride * nj.mbheight * c->ssy << 3))) njThrow(NJ_OUT_OF_MEM);
|
||||
}
|
||||
if (nj.ncomp == 3) {
|
||||
nj.rgb = (unsigned char*) njAllocMem(nj.width * nj.height * nj.ncomp);
|
||||
if (!nj.rgb) njThrow(NJ_OUT_OF_MEM);
|
||||
}
|
||||
njSkip(nj.length);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeDHT(void) {
|
||||
int codelen, currcnt, remain, spread, i, j;
|
||||
nj_vlc_code_t *vlc;
|
||||
static unsigned char counts[16];
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
while (nj.length >= 17) {
|
||||
i = nj.pos[0];
|
||||
if (i & 0xEC) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (i & 0x02) njThrow(NJ_UNSUPPORTED);
|
||||
i = (i | (i >> 3)) & 3; // combined DC/AC + tableid value
|
||||
for (codelen = 1; codelen <= 16; ++codelen)
|
||||
counts[codelen - 1] = nj.pos[codelen];
|
||||
njSkip(17);
|
||||
vlc = &nj.vlctab[i][0];
|
||||
remain = spread = 65536;
|
||||
for (codelen = 1; codelen <= 16; ++codelen) {
|
||||
spread >>= 1;
|
||||
currcnt = counts[codelen - 1];
|
||||
if (!currcnt) continue;
|
||||
if (nj.length < currcnt) njThrow(NJ_SYNTAX_ERROR);
|
||||
remain -= currcnt << (16 - codelen);
|
||||
if (remain < 0) njThrow(NJ_SYNTAX_ERROR);
|
||||
for (i = 0; i < currcnt; ++i) {
|
||||
register unsigned char code = nj.pos[i];
|
||||
for (j = spread; j; --j) {
|
||||
vlc->bits = (unsigned char) codelen;
|
||||
vlc->code = code;
|
||||
++vlc;
|
||||
}
|
||||
}
|
||||
njSkip(currcnt);
|
||||
}
|
||||
while (remain--) {
|
||||
vlc->bits = 0;
|
||||
++vlc;
|
||||
}
|
||||
}
|
||||
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeDQT(void) {
|
||||
int i;
|
||||
unsigned char *t;
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
while (nj.length >= 65) {
|
||||
i = nj.pos[0];
|
||||
if (i & 0xFC) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.qtavail |= 1 << i;
|
||||
t = &nj.qtab[i][0];
|
||||
for (i = 0; i < 64; ++i)
|
||||
t[i] = nj.pos[i + 1];
|
||||
njSkip(65);
|
||||
}
|
||||
if (nj.length) njThrow(NJ_SYNTAX_ERROR);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeDRI(void) {
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
if (nj.length < 2) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.rstinterval = njDecode16(nj.pos);
|
||||
njSkip(nj.length);
|
||||
}
|
||||
|
||||
static int njGetVLC(nj_vlc_code_t* vlc, unsigned char* code) {
|
||||
int value = njShowBits(16);
|
||||
int bits = vlc[value].bits;
|
||||
if (!bits) { nj.error = NJ_SYNTAX_ERROR; return 0; }
|
||||
njSkipBits(bits);
|
||||
value = vlc[value].code;
|
||||
if (code) *code = (unsigned char) value;
|
||||
bits = value & 15;
|
||||
if (!bits) return 0;
|
||||
value = njGetBits(bits);
|
||||
if (value < (1 << (bits - 1)))
|
||||
value += ((-1) << bits) + 1;
|
||||
return value;
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeBlock(nj_component_t* c, unsigned char* out) {
|
||||
unsigned char code = 0;
|
||||
int value, coef = 0;
|
||||
njFillMem(nj.block, 0, sizeof(nj.block));
|
||||
c->dcpred += njGetVLC(&nj.vlctab[c->dctabsel][0], NULL);
|
||||
nj.block[0] = (c->dcpred) * nj.qtab[c->qtsel][0];
|
||||
do {
|
||||
value = njGetVLC(&nj.vlctab[c->actabsel][0], &code);
|
||||
if (!code) break; // EOB
|
||||
if (!(code & 0x0F) && (code != 0xF0)) njThrow(NJ_SYNTAX_ERROR);
|
||||
coef += (code >> 4) + 1;
|
||||
if (coef > 63) njThrow(NJ_SYNTAX_ERROR);
|
||||
nj.block[(int) njZZ[coef]] = value * nj.qtab[c->qtsel][coef];
|
||||
} while (coef < 63);
|
||||
for (coef = 0; coef < 64; coef += 8)
|
||||
njRowIDCT(&nj.block[coef]);
|
||||
for (coef = 0; coef < 8; ++coef)
|
||||
njColIDCT(&nj.block[coef], &out[coef], c->stride);
|
||||
}
|
||||
|
||||
NJ_INLINE void njDecodeScan(void) {
|
||||
int i, mbx, mby, sbx, sby;
|
||||
int rstcount = nj.rstinterval, nextrst = 0;
|
||||
nj_component_t* c;
|
||||
njDecodeLength();
|
||||
njCheckError();
|
||||
if (nj.length < (4 + 2 * nj.ncomp)) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (nj.pos[0] != nj.ncomp) njThrow(NJ_UNSUPPORTED);
|
||||
njSkip(1);
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
if (nj.pos[0] != c->cid) njThrow(NJ_SYNTAX_ERROR);
|
||||
if (nj.pos[1] & 0xEE) njThrow(NJ_SYNTAX_ERROR);
|
||||
c->dctabsel = nj.pos[1] >> 4;
|
||||
c->actabsel = (nj.pos[1] & 1) | 2;
|
||||
njSkip(2);
|
||||
}
|
||||
if (nj.pos[0] || (nj.pos[1] != 63) || nj.pos[2]) njThrow(NJ_UNSUPPORTED);
|
||||
njSkip(nj.length);
|
||||
for (mbx = mby = 0;;) {
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c)
|
||||
for (sby = 0; sby < c->ssy; ++sby)
|
||||
for (sbx = 0; sbx < c->ssx; ++sbx) {
|
||||
njDecodeBlock(c, &c->pixels[((mby * c->ssy + sby) * c->stride + mbx * c->ssx + sbx) << 3]);
|
||||
njCheckError();
|
||||
}
|
||||
if (++mbx >= nj.mbwidth) {
|
||||
mbx = 0;
|
||||
if (++mby >= nj.mbheight) break;
|
||||
}
|
||||
if (nj.rstinterval && !(--rstcount)) {
|
||||
njByteAlign();
|
||||
i = njGetBits(16);
|
||||
if (((i & 0xFFF8) != 0xFFD0) || ((i & 7) != nextrst)) njThrow(NJ_SYNTAX_ERROR);
|
||||
nextrst = (nextrst + 1) & 7;
|
||||
rstcount = nj.rstinterval;
|
||||
for (i = 0; i < 3; ++i)
|
||||
nj.comp[i].dcpred = 0;
|
||||
}
|
||||
}
|
||||
nj.error = __NJ_FINISHED;
|
||||
}
|
||||
|
||||
#if NJ_CHROMA_FILTER
|
||||
|
||||
#define CF4A (-9)
|
||||
#define CF4B (111)
|
||||
#define CF4C (29)
|
||||
#define CF4D (-3)
|
||||
#define CF3A (28)
|
||||
#define CF3B (109)
|
||||
#define CF3C (-9)
|
||||
#define CF3X (104)
|
||||
#define CF3Y (27)
|
||||
#define CF3Z (-3)
|
||||
#define CF2A (139)
|
||||
#define CF2B (-11)
|
||||
#define CF(x) njClip(((x) + 64) >> 7)
|
||||
|
||||
NJ_INLINE void njUpsampleH(nj_component_t* c) {
|
||||
const int xmax = c->width - 3;
|
||||
unsigned char *out, *lin, *lout;
|
||||
int x, y;
|
||||
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
|
||||
if (!out) njThrow(NJ_OUT_OF_MEM);
|
||||
lin = c->pixels;
|
||||
lout = out;
|
||||
for (y = c->height; y; --y) {
|
||||
lout[0] = CF(CF2A * lin[0] + CF2B * lin[1]);
|
||||
lout[1] = CF(CF3X * lin[0] + CF3Y * lin[1] + CF3Z * lin[2]);
|
||||
lout[2] = CF(CF3A * lin[0] + CF3B * lin[1] + CF3C * lin[2]);
|
||||
for (x = 0; x < xmax; ++x) {
|
||||
lout[(x << 1) + 3] = CF(CF4A * lin[x] + CF4B * lin[x + 1] + CF4C * lin[x + 2] + CF4D * lin[x + 3]);
|
||||
lout[(x << 1) + 4] = CF(CF4D * lin[x] + CF4C * lin[x + 1] + CF4B * lin[x + 2] + CF4A * lin[x + 3]);
|
||||
}
|
||||
lin += c->stride;
|
||||
lout += c->width << 1;
|
||||
lout[-3] = CF(CF3A * lin[-1] + CF3B * lin[-2] + CF3C * lin[-3]);
|
||||
lout[-2] = CF(CF3X * lin[-1] + CF3Y * lin[-2] + CF3Z * lin[-3]);
|
||||
lout[-1] = CF(CF2A * lin[-1] + CF2B * lin[-2]);
|
||||
}
|
||||
c->width <<= 1;
|
||||
c->stride = c->width;
|
||||
njFreeMem((void*)c->pixels);
|
||||
c->pixels = out;
|
||||
}
|
||||
|
||||
NJ_INLINE void njUpsampleV(nj_component_t* c) {
|
||||
const int w = c->width, s1 = c->stride, s2 = s1 + s1;
|
||||
unsigned char *out, *cin, *cout;
|
||||
int x, y;
|
||||
out = (unsigned char*) njAllocMem((c->width * c->height) << 1);
|
||||
if (!out) njThrow(NJ_OUT_OF_MEM);
|
||||
for (x = 0; x < w; ++x) {
|
||||
cin = &c->pixels[x];
|
||||
cout = &out[x];
|
||||
*cout = CF(CF2A * cin[0] + CF2B * cin[s1]); cout += w;
|
||||
*cout = CF(CF3X * cin[0] + CF3Y * cin[s1] + CF3Z * cin[s2]); cout += w;
|
||||
*cout = CF(CF3A * cin[0] + CF3B * cin[s1] + CF3C * cin[s2]); cout += w;
|
||||
cin += s1;
|
||||
for (y = c->height - 3; y; --y) {
|
||||
*cout = CF(CF4A * cin[-s1] + CF4B * cin[0] + CF4C * cin[s1] + CF4D * cin[s2]); cout += w;
|
||||
*cout = CF(CF4D * cin[-s1] + CF4C * cin[0] + CF4B * cin[s1] + CF4A * cin[s2]); cout += w;
|
||||
cin += s1;
|
||||
}
|
||||
cin += s1;
|
||||
*cout = CF(CF3A * cin[0] + CF3B * cin[-s1] + CF3C * cin[-s2]); cout += w;
|
||||
*cout = CF(CF3X * cin[0] + CF3Y * cin[-s1] + CF3Z * cin[-s2]); cout += w;
|
||||
*cout = CF(CF2A * cin[0] + CF2B * cin[-s1]);
|
||||
}
|
||||
c->height <<= 1;
|
||||
c->stride = c->width;
|
||||
njFreeMem((void*) c->pixels);
|
||||
c->pixels = out;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
NJ_INLINE void njUpsample(nj_component_t* c) {
|
||||
int x, y, xshift = 0, yshift = 0;
|
||||
unsigned char *out, *lin, *lout;
|
||||
while (c->width < nj.width) { c->width <<= 1; ++xshift; }
|
||||
while (c->height < nj.height) { c->height <<= 1; ++yshift; }
|
||||
out = (unsigned char*) njAllocMem(c->width * c->height);
|
||||
if (!out) njThrow(NJ_OUT_OF_MEM);
|
||||
lin = c->pixels;
|
||||
lout = out;
|
||||
for (y = 0; y < c->height; ++y) {
|
||||
lin = &c->pixels[(y >> yshift) * c->stride];
|
||||
for (x = 0; x < c->width; ++x)
|
||||
lout[x] = lin[x >> xshift];
|
||||
lout += c->width;
|
||||
}
|
||||
c->stride = c->width;
|
||||
njFreeMem((void*) c->pixels);
|
||||
c->pixels = out;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
NJ_INLINE void njConvert(void) {
|
||||
int i;
|
||||
nj_component_t* c;
|
||||
for (i = 0, c = nj.comp; i < nj.ncomp; ++i, ++c) {
|
||||
#if NJ_CHROMA_FILTER
|
||||
while ((c->width < nj.width) || (c->height < nj.height)) {
|
||||
if (c->width < nj.width) njUpsampleH(c);
|
||||
njCheckError();
|
||||
if (c->height < nj.height) njUpsampleV(c);
|
||||
njCheckError();
|
||||
}
|
||||
#else
|
||||
if ((c->width < nj.width) || (c->height < nj.height))
|
||||
njUpsample(c);
|
||||
#endif
|
||||
if ((c->width < nj.width) || (c->height < nj.height)) njThrow(NJ_INTERNAL_ERR);
|
||||
}
|
||||
if (nj.ncomp == 3) {
|
||||
// convert to RGB
|
||||
int x, yy;
|
||||
unsigned char *prgb = nj.rgb;
|
||||
const unsigned char *py = nj.comp[0].pixels;
|
||||
const unsigned char *pcb = nj.comp[1].pixels;
|
||||
const unsigned char *pcr = nj.comp[2].pixels;
|
||||
for (yy = nj.height; yy; --yy) {
|
||||
for (x = 0; x < nj.width; ++x) {
|
||||
register int y = py[x] << 8;
|
||||
register int cb = pcb[x] - 128;
|
||||
register int cr = pcr[x] - 128;
|
||||
*prgb++ = njClip((y + 359 * cr + 128) >> 8);
|
||||
*prgb++ = njClip((y - 88 * cb - 183 * cr + 128) >> 8);
|
||||
*prgb++ = njClip((y + 454 * cb + 128) >> 8);
|
||||
}
|
||||
py += nj.comp[0].stride;
|
||||
pcb += nj.comp[1].stride;
|
||||
pcr += nj.comp[2].stride;
|
||||
}
|
||||
} else if (nj.comp[0].width != nj.comp[0].stride) {
|
||||
// grayscale -> only remove stride
|
||||
unsigned char *pin = &nj.comp[0].pixels[nj.comp[0].stride];
|
||||
unsigned char *pout = &nj.comp[0].pixels[nj.comp[0].width];
|
||||
int y;
|
||||
for (y = nj.comp[0].height - 1; y; --y) {
|
||||
njCopyMem(pout, pin, nj.comp[0].width);
|
||||
pin += nj.comp[0].stride;
|
||||
pout += nj.comp[0].width;
|
||||
}
|
||||
nj.comp[0].stride = nj.comp[0].width;
|
||||
}
|
||||
}
|
||||
|
||||
void njInit(void) {
|
||||
njFillMem(&nj, 0, sizeof(nj_context_t));
|
||||
}
|
||||
|
||||
void njDone(void) {
|
||||
int i;
|
||||
for (i = 0; i < 3; ++i)
|
||||
if (nj.comp[i].pixels) njFreeMem((void*) nj.comp[i].pixels);
|
||||
if (nj.rgb) njFreeMem((void*) nj.rgb);
|
||||
njInit();
|
||||
}
|
||||
|
||||
nj_result_t njDecode(const void* jpeg, const int size) {
|
||||
njDone();
|
||||
nj.pos = (const unsigned char*) jpeg;
|
||||
nj.size = size & 0x7FFFFFFF;
|
||||
if (nj.size < 2) return NJ_NO_JPEG;
|
||||
if ((nj.pos[0] ^ 0xFF) | (nj.pos[1] ^ 0xD8)) return NJ_NO_JPEG;
|
||||
njSkip(2);
|
||||
while (!nj.error) {
|
||||
if ((nj.size < 2) || (nj.pos[0] != 0xFF)) return NJ_SYNTAX_ERROR;
|
||||
njSkip(2);
|
||||
switch (nj.pos[-1]) {
|
||||
case 0xC0: njDecodeSOF(); break;
|
||||
case 0xC4: njDecodeDHT(); break;
|
||||
case 0xDB: njDecodeDQT(); break;
|
||||
case 0xDD: njDecodeDRI(); break;
|
||||
case 0xDA: njDecodeScan(); break;
|
||||
case 0xFE: njSkipMarker(); break;
|
||||
default:
|
||||
if ((nj.pos[-1] & 0xF0) == 0xE0)
|
||||
njSkipMarker();
|
||||
else
|
||||
return NJ_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
if (nj.error != __NJ_FINISHED) return nj.error;
|
||||
nj.error = NJ_OK;
|
||||
njConvert();
|
||||
return nj.error;
|
||||
}
|
||||
|
||||
int njGetWidth(void) { return nj.width; }
|
||||
int njGetHeight(void) { return nj.height; }
|
||||
int njIsColor(void) { return (nj.ncomp != 1); }
|
||||
unsigned char* njGetImage(void) { return (nj.ncomp == 1) ? nj.comp[0].pixels : nj.rgb; }
|
||||
int njGetImageSize(void) { return nj.width * nj.height * nj.ncomp; }
|
||||
|
||||
#endif // _NJ_INCLUDE_HEADER_ONLY
|
|
@ -0,0 +1,47 @@
|
|||
//============================================================================
|
||||
//
|
||||
// SSSS tt lll lll
|
||||
// SS SS tt ll ll
|
||||
// SS tttttt eeee ll ll aaaa
|
||||
// SSSS tt ee ee ll ll aa
|
||||
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
||||
// SS SS tt ee ll ll aa aa
|
||||
// SSSS ttt eeeee llll llll aaaaa
|
||||
//
|
||||
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
|
||||
// and the Stella Team
|
||||
//
|
||||
// See the file "License.txt" for information on usage and redistribution of
|
||||
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||||
//============================================================================
|
||||
|
||||
#ifndef NANOJPEG_LIB_HXX
|
||||
#define NANOJPEG_LIB_HXX
|
||||
|
||||
/*
|
||||
* We can't control the quality of code from outside projects, so for now
|
||||
* just disable warnings for it.
|
||||
*/
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Weverything"
|
||||
#include "nanojpeg.c"
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma GCC diagnostic ignored "-Wcast-function-type"
|
||||
#pragma GCC diagnostic ignored "-Wshift-negative-value"
|
||||
#pragma GCC diagnostic ignored "-Wregister"
|
||||
#include "nanojpeg.c"
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(BSPF_WINDOWS)
|
||||
#pragma warning(push, 0)
|
||||
#pragma warning(disable : 4706)
|
||||
#include "nanojpeg.c"
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#include "nanojpeg.c"
|
||||
#endif
|
||||
|
||||
#endif // NANOJPEG_LIB_HXX
|
|
@ -249,8 +249,8 @@
|
|||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
|
@ -283,8 +283,8 @@
|
|||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug-NoDebugger|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
|
@ -320,8 +320,8 @@
|
|||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
|
@ -356,8 +356,8 @@
|
|||
</Midl>
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;DEBUG_BUILD;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
|
@ -390,8 +390,8 @@
|
|||
<ClCompile>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
|
@ -425,8 +425,8 @@
|
|||
<ClCompile>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
|
@ -460,8 +460,8 @@
|
|||
<ClCompile>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
|
@ -499,8 +499,8 @@
|
|||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
|
@ -538,8 +538,8 @@
|
|||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;..\httplib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;HTTP_LIB_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
|
@ -577,8 +577,8 @@
|
|||
<Optimization>Full</Optimization>
|
||||
<InlineFunctionExpansion>Default</InlineFunctionExpansion>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;PNG_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>..\yacc;..\emucore;..\emucore\tia;..\emucore\tia\frame-manager;..\common;..\common\tv_filters;..\gui;..\debugger\gui;..\debugger;..\windows;..\cheat;..\zlib;..\libpng;..\json;..\common\repository\sqlite;..\sqlite;..\nanojpeg;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>BSPF_WINDOWS;WIN32;NOMINMAX;NDEBUG;SDL_SUPPORT;GUI_SUPPORT;IMAGE_SUPPORT;ZIP_SUPPORT;JOYSTICK_SUPPORT;DEBUGGER_SUPPORT;WINDOWED_SUPPORT;SOUND_SUPPORT;CHEATCODE_SUPPORT;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader>
|
||||
|
@ -624,6 +624,7 @@
|
|||
<ClCompile Include="..\common\FSNodeZIP.cxx" />
|
||||
<ClCompile Include="..\common\HighScoresManager.cxx" />
|
||||
<ClCompile Include="..\common\JoyMap.cxx" />
|
||||
<ClCompile Include="..\common\JPGLibrary.cxx" />
|
||||
<ClCompile Include="..\common\KeyMap.cxx" />
|
||||
<ClCompile Include="..\common\Logger.cxx" />
|
||||
<ClCompile Include="..\common\main.cxx" />
|
||||
|
@ -1799,6 +1800,7 @@
|
|||
<ClInclude Include="..\common\FSNodeZIP.hxx" />
|
||||
<ClInclude Include="..\common\HighScoresManager.hxx" />
|
||||
<ClInclude Include="..\common\JoyMap.hxx" />
|
||||
<ClInclude Include="..\common\JPGLibrary.hxx" />
|
||||
<ClInclude Include="..\common\jsonDefinitions.hxx" />
|
||||
<ClInclude Include="..\common\KeyMap.hxx" />
|
||||
<ClInclude Include="..\common\LinkedObjectPool.hxx" />
|
||||
|
@ -2168,6 +2170,7 @@
|
|||
<ClInclude Include="..\libpng\pnginfo.h" />
|
||||
<ClInclude Include="..\libpng\pnglibconf.h" />
|
||||
<ClInclude Include="..\libpng\pngstruct.h" />
|
||||
<ClInclude Include="..\nanojpeg\nanojpeg_lib.hxx" />
|
||||
<ClInclude Include="..\sqlite\source\sqlite3.h" />
|
||||
<ClInclude Include="..\sqlite\sqlite3.h" />
|
||||
<ClInclude Include="..\sqlite\sqlite_options.h" />
|
||||
|
|
|
@ -94,6 +94,9 @@
|
|||
<Filter Include="Header Files\httplib">
|
||||
<UniqueIdentifier>{e216a718-4078-4a08-b134-4987ec071e31}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\nanojpeg">
|
||||
<UniqueIdentifier>{7836da03-0e67-481a-b16a-529a1042d215}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\common\FBBackendSDL2.cxx">
|
||||
|
@ -1149,6 +1152,9 @@
|
|||
<ClCompile Include="..\gui\RomImageWidget.cxx">
|
||||
<Filter>Source Files\gui</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\common\JPGLibrary.cxx">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\common\bspf.hxx">
|
||||
|
@ -2378,6 +2384,12 @@
|
|||
<ClInclude Include="..\gui\RomImageWidget.hxx">
|
||||
<Filter>Header Files\gui</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\common\JPGLibrary.hxx">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\nanojpeg\nanojpeg_lib.hxx">
|
||||
<Filter>Header Files\nanojpeg</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="stella.ico">
|
||||
|
|
Loading…
Reference in New Issue