mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 02:23:47 +00:00
# Animate props.
tex: Reverted recent WARN_RETURN(ERR_TEX_CODEC_CANNOT_HANDLE) changes, since (I think) it shouldn't warn about that being returned (because it intentionally happens frequently). XMLWriter: Trivial inconsequential optimisations (avoiding temporary strings). This was SVN commit r3801.
This commit is contained in:
@@ -406,7 +406,7 @@ bool CModel::SetAnimation(CSkeletonAnim* anim, bool once, float speed, CSkeleton
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddProp: add a prop to the model on the given point
|
||||
void CModel::AddProp(SPropPoint* point, CModel* model)
|
||||
void CModel::AddProp(SPropPoint* point, CModel* model, CObjectEntry* objectentry)
|
||||
{
|
||||
// position model according to prop point position
|
||||
model->SetTransform(point->m_Transform);
|
||||
@@ -415,8 +415,8 @@ void CModel::AddProp(SPropPoint* point, CModel* model)
|
||||
// check if we're already using this point, and remove it if so
|
||||
// (when a prop is removed it will also remove the prop point)
|
||||
uint i;
|
||||
for (i=0;i<m_Props.size();i++) {
|
||||
if (m_Props[i].m_Point==point) {
|
||||
for (i = 0; i < m_Props.size(); i++) {
|
||||
if (m_Props[i].m_Point == point) {
|
||||
delete m_Props[i].m_Model;
|
||||
break;
|
||||
}
|
||||
@@ -424,8 +424,9 @@ void CModel::AddProp(SPropPoint* point, CModel* model)
|
||||
|
||||
// not using point; add new prop
|
||||
Prop prop;
|
||||
prop.m_Point=point;
|
||||
prop.m_Model=model;
|
||||
prop.m_Point = point;
|
||||
prop.m_Model = model;
|
||||
prop.m_ObjectEntry = objectentry;
|
||||
m_Props.push_back(prop);
|
||||
}
|
||||
|
||||
@@ -458,7 +459,7 @@ CModel* CModel::Clone() const
|
||||
clone->SetFlags(m_Flags);
|
||||
for (uint i=0;i<m_Props.size();i++) {
|
||||
// eek! TODO, RC - need to investigate shallow clone here
|
||||
clone->AddProp(m_Props[i].m_Point, m_Props[i].m_Model->Clone());
|
||||
clone->AddProp(m_Props[i].m_Point, m_Props[i].m_Model->Clone(), m_Props[i].m_ObjectEntry);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
#include "Texture.h"
|
||||
#include "MeshManager.h"
|
||||
#include "RenderableObject.h"
|
||||
#include "SkeletonAnim.h"
|
||||
#include "Material.h"
|
||||
#include "Overlay.h"
|
||||
struct SPropPoint;
|
||||
class CObjectEntry;
|
||||
class CSkeletonAnim;
|
||||
class CSkeletonAnimDef;
|
||||
|
||||
#define MODELFLAG_CASTSHADOWS (1<<0)
|
||||
#define MODELFLAG_NOLOOPANIMATION (1<<1)
|
||||
@@ -29,10 +31,11 @@ class CModel : public CRenderableObject
|
||||
{
|
||||
public:
|
||||
struct Prop {
|
||||
Prop() : m_Point(0), m_Model(0) {}
|
||||
Prop() : m_Point(0), m_Model(0), m_ObjectEntry(0) {}
|
||||
|
||||
SPropPoint* m_Point;
|
||||
CModel* m_Model;
|
||||
CObjectEntry* m_ObjectEntry;
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -119,7 +122,7 @@ public:
|
||||
CSkeletonAnim* BuildAnimation(const char* filename, const char* name, float speed, double actionpos, double actionpos2);
|
||||
|
||||
// add a prop to the model on the given point
|
||||
void AddProp(SPropPoint* point,CModel* model);
|
||||
void AddProp(SPropPoint* point, CModel* model, CObjectEntry* objectentry);
|
||||
// remove a prop from the given point
|
||||
void RemoveProp(SPropPoint* point);
|
||||
// return prop list
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "CLogger.h"
|
||||
#include "MaterialManager.h"
|
||||
#include "MeshManager.h"
|
||||
#include "SkeletonAnim.h"
|
||||
|
||||
#include "UnitManager.h"
|
||||
#include "Unit.h"
|
||||
@@ -164,7 +165,7 @@ bool CObjectEntry::BuildVariation(const std::vector<std::set<CStrW> >& selection
|
||||
if (proppoint)
|
||||
{
|
||||
CModel* propmodel = oe->m_Model->Clone();
|
||||
m_Model->AddProp(proppoint, propmodel);
|
||||
m_Model->AddProp(proppoint, propmodel, oe);
|
||||
propmodel->SetAnimation(oe->GetRandomAnimation("idle"));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
|
||||
class CModel;
|
||||
class CSkeletonAnim;
|
||||
class CObjectBase;
|
||||
struct SPropPoint;
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "CStr.h"
|
||||
#include "ObjectBase.h"
|
||||
#include "Overlay.h"
|
||||
|
||||
class CObjectEntry
|
||||
|
||||
+40
-15
@@ -4,6 +4,7 @@
|
||||
#include "Model.h"
|
||||
#include "ObjectEntry.h"
|
||||
#include "ObjectManager.h"
|
||||
#include "SkeletonAnim.h"
|
||||
#include "SkeletonAnimDef.h"
|
||||
|
||||
CUnit::CUnit(CObjectEntry* object, CEntity* entity, const std::set<CStrW>& actorSelections)
|
||||
@@ -22,7 +23,7 @@ void CUnit::ShowAmmunition()
|
||||
{
|
||||
if (!m_Object->m_AmmunitionModel || !m_Object->m_AmmunitionPoint)
|
||||
return;
|
||||
m_Model->AddProp(m_Object->m_AmmunitionPoint, m_Object->m_AmmunitionModel->Clone());
|
||||
m_Model->AddProp(m_Object->m_AmmunitionPoint, m_Object->m_AmmunitionModel->Clone(), m_Object);
|
||||
}
|
||||
|
||||
void CUnit::HideAmmunition()
|
||||
@@ -37,7 +38,7 @@ void CUnit::HideAmmunition()
|
||||
{
|
||||
if (it->m_Point == m_Object->m_AmmunitionPoint)
|
||||
{
|
||||
m_Model->AddProp(m_Object->m_AmmunitionPoint, it->m_Model->Clone());
|
||||
m_Model->AddProp(m_Object->m_AmmunitionPoint, it->m_Model->Clone(), m_Object);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -45,15 +46,41 @@ void CUnit::HideAmmunition()
|
||||
m_Model->RemoveProp(m_Object->m_AmmunitionPoint);
|
||||
}
|
||||
|
||||
bool CUnit::SetRandomAnimation(const CStr& name, bool once, float speed)
|
||||
|
||||
static CSkeletonAnim* GetRandomAnimation(const CStr& name, CObjectEntry* object)
|
||||
{
|
||||
CSkeletonAnim* anim = GetRandomAnimation(name);
|
||||
CSkeletonAnim* anim = object->GetRandomAnimation(name);
|
||||
|
||||
// Fall back to 'idle', if no matching animation is found
|
||||
if (anim == NULL && name != "idle")
|
||||
anim = object->GetRandomAnimation("idle");
|
||||
|
||||
// Every object should have an idle animation (even if it's a dummy static one)
|
||||
debug_assert(anim != NULL);
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
static bool SetRandomAnimation(const CStr& name, bool once, float speed,
|
||||
CModel* model, CObjectEntry* object)
|
||||
{
|
||||
CSkeletonAnim* anim = GetRandomAnimation(name, object);
|
||||
if (anim)
|
||||
{
|
||||
float actualSpeed = 1000.f;
|
||||
if (speed && anim->m_AnimDef)
|
||||
actualSpeed = speed * anim->m_AnimDef->GetDuration();
|
||||
m_Model->SetAnimation(anim, once, actualSpeed);
|
||||
model->SetAnimation(anim, once, actualSpeed);
|
||||
|
||||
// Recursively apply the animation name to props
|
||||
const std::vector<CModel::Prop>& props = model->GetProps();
|
||||
for (std::vector<CModel::Prop>::const_iterator it = props.begin(); it != props.end(); ++it)
|
||||
{
|
||||
bool ok = SetRandomAnimation(name, once, speed, it->m_Model, it->m_ObjectEntry);
|
||||
if (! ok)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -64,18 +91,16 @@ bool CUnit::SetRandomAnimation(const CStr& name, bool once, float speed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CUnit::SetRandomAnimation(const CStr& name, bool once, float speed)
|
||||
{
|
||||
return ::SetRandomAnimation(name, once, speed, m_Model, m_Object);
|
||||
}
|
||||
|
||||
CSkeletonAnim* CUnit::GetRandomAnimation(const CStr& name)
|
||||
{
|
||||
CSkeletonAnim* anim = m_Object->GetRandomAnimation(name);
|
||||
|
||||
// Fall back to 'idle', if no matching animation is found
|
||||
if (anim == NULL && name != "idle")
|
||||
anim = m_Object->GetRandomAnimation("idle");
|
||||
|
||||
// Every object should have an idle animation (even if it's a dummy static one)
|
||||
debug_assert(anim != NULL);
|
||||
|
||||
return anim;
|
||||
return ::GetRandomAnimation(name, m_Object);
|
||||
}
|
||||
|
||||
bool CUnit::IsPlayingAnimation(const CStr& name)
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
void HideAmmunition();
|
||||
|
||||
// Sets the animation a random one matching 'name'. If none is found,
|
||||
// sets to idle instead.
|
||||
// sets to idle instead. Applies recursively to props.
|
||||
bool SetRandomAnimation(const CStr8& name, bool once = false, float speed = 0.0f);
|
||||
|
||||
// Returns a random animation matching 'name'. If none is found,
|
||||
|
||||
@@ -207,7 +207,7 @@ TIMER_ACCRUE(tc_plain_transform);
|
||||
// sanity checks (not errors, we just can't handle these cases)
|
||||
// .. unknown transform
|
||||
if(transforms & ~(TEX_BGR|TEX_ORIENTATION|TEX_MIPMAPS))
|
||||
WARN_RETURN(ERR_TEX_CODEC_CANNOT_HANDLE);
|
||||
return ERR_TEX_CODEC_CANNOT_HANDLE;
|
||||
// .. data is not in "plain" format
|
||||
RETURN_ERR(tex_validate_plain_format(bpp, flags));
|
||||
// .. nothing to do
|
||||
|
||||
@@ -58,7 +58,7 @@ struct BmpHeader
|
||||
|
||||
static LibError bmp_transform(Tex* UNUSED(t), uint UNUSED(transforms))
|
||||
{
|
||||
WARN_RETURN(ERR_TEX_CODEC_CANNOT_HANDLE);
|
||||
return ERR_TEX_CODEC_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -626,7 +626,7 @@ static LibError dds_encode(Tex* restrict UNUSED(t), DynArray* restrict UNUSED(da
|
||||
{
|
||||
// note: do not return ERR_NOT_IMPLEMENTED et al. because that would
|
||||
// break tex_write (which assumes either this, 0 or errors are returned).
|
||||
WARN_RETURN(ERR_TEX_CODEC_CANNOT_HANDLE);
|
||||
return ERR_TEX_CODEC_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+295
-295
@@ -22,17 +22,17 @@
|
||||
|
||||
#include "precompiled.h"
|
||||
|
||||
extern "C" {
|
||||
// this is not a core library module, so it doesn't define JPEG_INTERNALS
|
||||
#include "jpeglib.h"
|
||||
#include "jerror.h"
|
||||
}
|
||||
extern "C" {
|
||||
// this is not a core library module, so it doesn't define JPEG_INTERNALS
|
||||
#include "jpeglib.h"
|
||||
#include "jerror.h"
|
||||
}
|
||||
|
||||
#include "lib.h"
|
||||
#include "lib/res/res.h"
|
||||
#include "tex_codec.h"
|
||||
#include <setjmp.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
|
||||
|
||||
#if MSC_VERSION
|
||||
|
||||
@@ -51,293 +51,293 @@ extern "C" {
|
||||
# endif // #ifdef NDEBUG
|
||||
|
||||
#endif // #ifdef MSC_VERSION
|
||||
|
||||
|
||||
|
||||
/* IMPORTANT: we assume that JOCTET is 8 bits. */
|
||||
cassert(sizeof(JOCTET) == 1 && CHAR_BIT == 8);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// mem source manager
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* Expanded data source object for memory input */
|
||||
typedef struct
|
||||
{
|
||||
struct jpeg_source_mgr pub; /* public fields */
|
||||
DynArray* da;
|
||||
}
|
||||
SrcMgr;
|
||||
typedef SrcMgr* SrcPtr;
|
||||
|
||||
|
||||
/*
|
||||
* Initialize source --- called by jpeg_read_header
|
||||
* before any data is actually read.
|
||||
*/
|
||||
|
||||
METHODDEF(void) src_init(j_decompress_ptr UNUSED(cinfo))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fill the input buffer --- called whenever buffer is emptied.
|
||||
*
|
||||
* In typical applications, this should read fresh data into the buffer
|
||||
* (ignoring the current state of next_input_byte & bytes_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been reloaded. It is not necessary to
|
||||
* fill the buffer entirely, only to obtain at least one more byte.
|
||||
*
|
||||
* There is no such thing as an EOF return. If the end of the file has been
|
||||
* reached, the routine has a choice of ERREXIT() or inserting fake data into
|
||||
* the buffer. In most cases, generating a warning message and inserting a
|
||||
* fake EOI marker is the best course of action --- this will allow the
|
||||
* decompressor to output however much of the image is there. However,
|
||||
* the resulting error message is misleading if the real problem is an empty
|
||||
* input file, so we handle that case specially.
|
||||
*/
|
||||
|
||||
METHODDEF(boolean) src_fill_buffer(j_decompress_ptr cinfo)
|
||||
{
|
||||
SrcPtr src = (SrcPtr)cinfo->src;
|
||||
static const JOCTET eoi[2] = { 0xFF, JPEG_EOI };
|
||||
|
||||
/*
|
||||
* since jpeg_mem_src fills the buffer with everything we've got,
|
||||
* jpeg is trying to read beyond end of buffer. return a fake EOI marker.
|
||||
* note: don't modify input buffer: it might be read-only.
|
||||
*/
|
||||
|
||||
WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||
|
||||
src->pub.next_input_byte = eoi;
|
||||
src->pub.bytes_in_buffer = 2;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Skip data --- used to skip over a potentially large amount of
|
||||
* uninteresting data (such as an APPn marker).
|
||||
*/
|
||||
|
||||
METHODDEF(void) src_skip_data(j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
SrcPtr src = (SrcPtr)cinfo->src;
|
||||
size_t skip_count = (size_t)num_bytes;
|
||||
|
||||
/* docs say non-positive num_byte skips should be ignored */
|
||||
if(num_bytes <= 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* just subtract bytes available in buffer,
|
||||
* making sure we don't underflow the size_t.
|
||||
* note: if we skip to or beyond end of buffer,
|
||||
* bytes_in_buffer = 0 => fill_input_buffer called => abort.
|
||||
*/
|
||||
if(skip_count > src->pub.bytes_in_buffer)
|
||||
skip_count = src->pub.bytes_in_buffer;
|
||||
|
||||
src->pub.bytes_in_buffer -= skip_count;
|
||||
src->pub.next_input_byte += skip_count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* An additional method that can be provided by data source modules is the
|
||||
* resync_to_restart method for error recovery in the presence of RST markers.
|
||||
* For the moment, this source module just uses the default resync method
|
||||
* provided by the JPEG library. That method assumes that no backtracking
|
||||
* is possible.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Terminate source --- called by jpeg_finish_decompress
|
||||
* after all data has been read. Often a no-op.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
METHODDEF(void) src_term(j_decompress_ptr UNUSED(cinfo))
|
||||
{
|
||||
/*
|
||||
* no-op (we don't own the buffer and shouldn't,
|
||||
* to make possible multiple images in a source).
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for input from a buffer.
|
||||
* The caller is responsible for freeing it after finishing decompression.
|
||||
*/
|
||||
|
||||
GLOBAL(void) src_prepare(j_decompress_ptr cinfo, DynArray* da)
|
||||
{
|
||||
SrcPtr src;
|
||||
|
||||
const u8* p = da->base;
|
||||
const size_t size = da->cur_size;
|
||||
|
||||
/* Treat 0-length buffer as fatal error */
|
||||
if(size == 0)
|
||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
|
||||
/*
|
||||
* The source object is made permanent so that
|
||||
* a series of JPEG images can be read from the same file
|
||||
* by calling jpeg_mem_src only before the first one.
|
||||
* This makes it unsafe to use this manager and a different source
|
||||
* manager serially with the same JPEG object. Caveat programmer.
|
||||
*/
|
||||
|
||||
/* first time for this JPEG object? */
|
||||
if(!cinfo->src)
|
||||
cinfo->src = (struct jpeg_source_mgr*)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
|
||||
sizeof(SrcMgr));
|
||||
/* (takes care of raising error if out of memory) */
|
||||
|
||||
src = (SrcPtr)cinfo->src;
|
||||
src->pub.init_source = src_init;
|
||||
src->pub.fill_input_buffer = src_fill_buffer;
|
||||
src->pub.skip_input_data = src_skip_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart; /* default */
|
||||
src->pub.term_source = src_term;
|
||||
|
||||
/*
|
||||
* fill buffer with everything we have.
|
||||
* if fill_input_buffer is called, the buffer was overrun.
|
||||
*/
|
||||
src->pub.bytes_in_buffer = size;
|
||||
src->pub.next_input_byte = (JOCTET*)p;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// mem destination manager
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/* Expanded data destination object for memory output */
|
||||
typedef struct {
|
||||
struct jpeg_destination_mgr pub; /* public fields */
|
||||
DynArray* da;
|
||||
} DstMgr;
|
||||
|
||||
typedef DstMgr* DstPtr;
|
||||
|
||||
// this affects how often dst_empty_output_buffer is called (which
|
||||
// efficiently expands the DynArray) and how much tail memory we waste
|
||||
// (not an issue because it is freed immediately after compression).
|
||||
#define OUTPUT_BUF_SIZE 64*KiB /* choose an efficiently writeable size */
|
||||
|
||||
// note: can't call dst_empty_output_buffer from dst_init or vice versa
|
||||
// because only the former must advance da->pos.
|
||||
static void make_room_in_buffer(j_compress_ptr cinfo)
|
||||
|
||||
|
||||
/* IMPORTANT: we assume that JOCTET is 8 bits. */
|
||||
cassert(sizeof(JOCTET) == 1 && CHAR_BIT == 8);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// mem source manager
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/* Expanded data source object for memory input */
|
||||
typedef struct
|
||||
{
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
DynArray* da = dst->da;
|
||||
|
||||
void* start = da->base + da->cur_size;
|
||||
|
||||
if(da_set_size(da, da->cur_size+OUTPUT_BUF_SIZE) != 0)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
|
||||
dst->pub.next_output_byte = (JOCTET*)start;
|
||||
dst->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize destination --- called by jpeg_start_compress
|
||||
* before any data is actually written.
|
||||
*/
|
||||
METHODDEF(void) dst_init(j_compress_ptr cinfo)
|
||||
{
|
||||
make_room_in_buffer(cinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Empty the output buffer --- called whenever buffer fills up.
|
||||
*
|
||||
* In typical applications, this should write the entire output buffer
|
||||
* (ignoring the current state of next_output_byte & free_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been dumped.
|
||||
*
|
||||
* <snip comments on suspended IO>
|
||||
*/
|
||||
METHODDEF(boolean) dst_empty_output_buffer(j_compress_ptr cinfo)
|
||||
{
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
DynArray* da = dst->da;
|
||||
|
||||
// writing out OUTPUT_BUF_SIZE-dst->pub.free_in_buffer bytes
|
||||
// sounds reasonable, but makes for broken output.
|
||||
da->pos += OUTPUT_BUF_SIZE;
|
||||
|
||||
make_room_in_buffer(cinfo);
|
||||
|
||||
return TRUE; // not suspended
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Terminate destination --- called by jpeg_finish_compress
|
||||
* after all data has been written. Usually needs to flush buffer.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
METHODDEF(void) dst_term(j_compress_ptr cinfo)
|
||||
{
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
DynArray* da = dst->da;
|
||||
|
||||
// account for nbytes left in buffer
|
||||
da->pos += OUTPUT_BUF_SIZE - dst->pub.free_in_buffer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for output to a buffer.
|
||||
* The caller is responsible for allocating and writing out to disk after
|
||||
* compression is complete.
|
||||
*/
|
||||
|
||||
GLOBAL(void) dst_prepare(j_compress_ptr cinfo, DynArray* da)
|
||||
{
|
||||
/* The destination object is made permanent so that multiple JPEG images
|
||||
* can be written to the same file without re-executing dst_prepare.
|
||||
* This makes it dangerous to use this manager and a different destination
|
||||
* manager serially with the same JPEG object, because their private object
|
||||
* sizes may be different. Caveat programmer.
|
||||
*/
|
||||
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr*)(*cinfo->mem->alloc_small)
|
||||
((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(DstMgr));
|
||||
}
|
||||
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
dst->pub.init_destination = dst_init;
|
||||
dst->pub.empty_output_buffer = dst_empty_output_buffer;
|
||||
dst->pub.term_destination = dst_term;
|
||||
dst->da = da;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// error handler, shared by jpg_(en|de)code
|
||||
//-----------------------------------------------------------------------------
|
||||
struct jpeg_source_mgr pub; /* public fields */
|
||||
DynArray* da;
|
||||
}
|
||||
SrcMgr;
|
||||
typedef SrcMgr* SrcPtr;
|
||||
|
||||
|
||||
/*
|
||||
* Initialize source --- called by jpeg_read_header
|
||||
* before any data is actually read.
|
||||
*/
|
||||
|
||||
METHODDEF(void) src_init(j_decompress_ptr UNUSED(cinfo))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Fill the input buffer --- called whenever buffer is emptied.
|
||||
*
|
||||
* In typical applications, this should read fresh data into the buffer
|
||||
* (ignoring the current state of next_input_byte & bytes_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been reloaded. It is not necessary to
|
||||
* fill the buffer entirely, only to obtain at least one more byte.
|
||||
*
|
||||
* There is no such thing as an EOF return. If the end of the file has been
|
||||
* reached, the routine has a choice of ERREXIT() or inserting fake data into
|
||||
* the buffer. In most cases, generating a warning message and inserting a
|
||||
* fake EOI marker is the best course of action --- this will allow the
|
||||
* decompressor to output however much of the image is there. However,
|
||||
* the resulting error message is misleading if the real problem is an empty
|
||||
* input file, so we handle that case specially.
|
||||
*/
|
||||
|
||||
METHODDEF(boolean) src_fill_buffer(j_decompress_ptr cinfo)
|
||||
{
|
||||
SrcPtr src = (SrcPtr)cinfo->src;
|
||||
static const JOCTET eoi[2] = { 0xFF, JPEG_EOI };
|
||||
|
||||
/*
|
||||
* since jpeg_mem_src fills the buffer with everything we've got,
|
||||
* jpeg is trying to read beyond end of buffer. return a fake EOI marker.
|
||||
* note: don't modify input buffer: it might be read-only.
|
||||
*/
|
||||
|
||||
WARNMS(cinfo, JWRN_JPEG_EOF);
|
||||
|
||||
src->pub.next_input_byte = eoi;
|
||||
src->pub.bytes_in_buffer = 2;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Skip data --- used to skip over a potentially large amount of
|
||||
* uninteresting data (such as an APPn marker).
|
||||
*/
|
||||
|
||||
METHODDEF(void) src_skip_data(j_decompress_ptr cinfo, long num_bytes)
|
||||
{
|
||||
SrcPtr src = (SrcPtr)cinfo->src;
|
||||
size_t skip_count = (size_t)num_bytes;
|
||||
|
||||
/* docs say non-positive num_byte skips should be ignored */
|
||||
if(num_bytes <= 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* just subtract bytes available in buffer,
|
||||
* making sure we don't underflow the size_t.
|
||||
* note: if we skip to or beyond end of buffer,
|
||||
* bytes_in_buffer = 0 => fill_input_buffer called => abort.
|
||||
*/
|
||||
if(skip_count > src->pub.bytes_in_buffer)
|
||||
skip_count = src->pub.bytes_in_buffer;
|
||||
|
||||
src->pub.bytes_in_buffer -= skip_count;
|
||||
src->pub.next_input_byte += skip_count;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* An additional method that can be provided by data source modules is the
|
||||
* resync_to_restart method for error recovery in the presence of RST markers.
|
||||
* For the moment, this source module just uses the default resync method
|
||||
* provided by the JPEG library. That method assumes that no backtracking
|
||||
* is possible.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Terminate source --- called by jpeg_finish_decompress
|
||||
* after all data has been read. Often a no-op.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
|
||||
METHODDEF(void) src_term(j_decompress_ptr UNUSED(cinfo))
|
||||
{
|
||||
/*
|
||||
* no-op (we don't own the buffer and shouldn't,
|
||||
* to make possible multiple images in a source).
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for input from a buffer.
|
||||
* The caller is responsible for freeing it after finishing decompression.
|
||||
*/
|
||||
|
||||
GLOBAL(void) src_prepare(j_decompress_ptr cinfo, DynArray* da)
|
||||
{
|
||||
SrcPtr src;
|
||||
|
||||
const u8* p = da->base;
|
||||
const size_t size = da->cur_size;
|
||||
|
||||
/* Treat 0-length buffer as fatal error */
|
||||
if(size == 0)
|
||||
ERREXIT(cinfo, JERR_INPUT_EMPTY);
|
||||
|
||||
/*
|
||||
* The source object is made permanent so that
|
||||
* a series of JPEG images can be read from the same file
|
||||
* by calling jpeg_mem_src only before the first one.
|
||||
* This makes it unsafe to use this manager and a different source
|
||||
* manager serially with the same JPEG object. Caveat programmer.
|
||||
*/
|
||||
|
||||
/* first time for this JPEG object? */
|
||||
if(!cinfo->src)
|
||||
cinfo->src = (struct jpeg_source_mgr*)
|
||||
(*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_PERMANENT,
|
||||
sizeof(SrcMgr));
|
||||
/* (takes care of raising error if out of memory) */
|
||||
|
||||
src = (SrcPtr)cinfo->src;
|
||||
src->pub.init_source = src_init;
|
||||
src->pub.fill_input_buffer = src_fill_buffer;
|
||||
src->pub.skip_input_data = src_skip_data;
|
||||
src->pub.resync_to_restart = jpeg_resync_to_restart; /* default */
|
||||
src->pub.term_source = src_term;
|
||||
|
||||
/*
|
||||
* fill buffer with everything we have.
|
||||
* if fill_input_buffer is called, the buffer was overrun.
|
||||
*/
|
||||
src->pub.bytes_in_buffer = size;
|
||||
src->pub.next_input_byte = (JOCTET*)p;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// mem destination manager
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/* Expanded data destination object for memory output */
|
||||
typedef struct {
|
||||
struct jpeg_destination_mgr pub; /* public fields */
|
||||
DynArray* da;
|
||||
} DstMgr;
|
||||
|
||||
typedef DstMgr* DstPtr;
|
||||
|
||||
// this affects how often dst_empty_output_buffer is called (which
|
||||
// efficiently expands the DynArray) and how much tail memory we waste
|
||||
// (not an issue because it is freed immediately after compression).
|
||||
#define OUTPUT_BUF_SIZE 64*KiB /* choose an efficiently writeable size */
|
||||
|
||||
// note: can't call dst_empty_output_buffer from dst_init or vice versa
|
||||
// because only the former must advance da->pos.
|
||||
static void make_room_in_buffer(j_compress_ptr cinfo)
|
||||
{
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
DynArray* da = dst->da;
|
||||
|
||||
void* start = da->base + da->cur_size;
|
||||
|
||||
if(da_set_size(da, da->cur_size+OUTPUT_BUF_SIZE) != 0)
|
||||
ERREXIT(cinfo, JERR_FILE_WRITE);
|
||||
|
||||
dst->pub.next_output_byte = (JOCTET*)start;
|
||||
dst->pub.free_in_buffer = OUTPUT_BUF_SIZE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize destination --- called by jpeg_start_compress
|
||||
* before any data is actually written.
|
||||
*/
|
||||
METHODDEF(void) dst_init(j_compress_ptr cinfo)
|
||||
{
|
||||
make_room_in_buffer(cinfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Empty the output buffer --- called whenever buffer fills up.
|
||||
*
|
||||
* In typical applications, this should write the entire output buffer
|
||||
* (ignoring the current state of next_output_byte & free_in_buffer),
|
||||
* reset the pointer & count to the start of the buffer, and return TRUE
|
||||
* indicating that the buffer has been dumped.
|
||||
*
|
||||
* <snip comments on suspended IO>
|
||||
*/
|
||||
METHODDEF(boolean) dst_empty_output_buffer(j_compress_ptr cinfo)
|
||||
{
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
DynArray* da = dst->da;
|
||||
|
||||
// writing out OUTPUT_BUF_SIZE-dst->pub.free_in_buffer bytes
|
||||
// sounds reasonable, but makes for broken output.
|
||||
da->pos += OUTPUT_BUF_SIZE;
|
||||
|
||||
make_room_in_buffer(cinfo);
|
||||
|
||||
return TRUE; // not suspended
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Terminate destination --- called by jpeg_finish_compress
|
||||
* after all data has been written. Usually needs to flush buffer.
|
||||
*
|
||||
* NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
|
||||
* application must deal with any cleanup that should happen even
|
||||
* for error exit.
|
||||
*/
|
||||
METHODDEF(void) dst_term(j_compress_ptr cinfo)
|
||||
{
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
DynArray* da = dst->da;
|
||||
|
||||
// account for nbytes left in buffer
|
||||
da->pos += OUTPUT_BUF_SIZE - dst->pub.free_in_buffer;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prepare for output to a buffer.
|
||||
* The caller is responsible for allocating and writing out to disk after
|
||||
* compression is complete.
|
||||
*/
|
||||
|
||||
GLOBAL(void) dst_prepare(j_compress_ptr cinfo, DynArray* da)
|
||||
{
|
||||
/* The destination object is made permanent so that multiple JPEG images
|
||||
* can be written to the same file without re-executing dst_prepare.
|
||||
* This makes it dangerous to use this manager and a different destination
|
||||
* manager serially with the same JPEG object, because their private object
|
||||
* sizes may be different. Caveat programmer.
|
||||
*/
|
||||
if (cinfo->dest == NULL) { /* first time for this JPEG object? */
|
||||
cinfo->dest = (struct jpeg_destination_mgr*)(*cinfo->mem->alloc_small)
|
||||
((j_common_ptr)cinfo, JPOOL_PERMANENT, sizeof(DstMgr));
|
||||
}
|
||||
|
||||
DstPtr dst = (DstPtr)cinfo->dest;
|
||||
dst->pub.init_destination = dst_init;
|
||||
dst->pub.empty_output_buffer = dst_empty_output_buffer;
|
||||
dst->pub.term_destination = dst_term;
|
||||
dst->da = da;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// error handler, shared by jpg_(en|de)code
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// the JPEG library's standard error handler (jerror.c) is divided into
|
||||
// several "methods" which we can override individually. This allows
|
||||
@@ -416,13 +416,13 @@ JpgErrorMgr::JpgErrorMgr(j_common_ptr cinfo)
|
||||
cinfo->err = &pub;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
static LibError jpg_transform(Tex* UNUSED(t), uint UNUSED(transforms))
|
||||
{
|
||||
WARN_RETURN(ERR_TEX_CODEC_CANNOT_HANDLE);
|
||||
return ERR_TEX_CODEC_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ static void io_flush(png_structp UNUSED(png_ptr))
|
||||
|
||||
static LibError png_transform(Tex* UNUSED(t), uint UNUSED(transforms))
|
||||
{
|
||||
WARN_RETURN(ERR_TEX_CODEC_CANNOT_HANDLE);
|
||||
return ERR_TEX_CODEC_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ TgaHeader;
|
||||
|
||||
static LibError tga_transform(Tex* UNUSED(t), uint UNUSED(transforms))
|
||||
{
|
||||
WARN_RETURN(ERR_TEX_CODEC_CANNOT_HANDLE);
|
||||
return ERR_TEX_CODEC_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -60,7 +60,10 @@ void XMLWriter_File::ElementStart(XMLWriter_Element* element, const char* name)
|
||||
{
|
||||
if (m_LastElement) m_LastElement->Close(EL_SUBEL);
|
||||
m_LastElement = element;
|
||||
m_Data += "\n" + Indent() + "<" + name;
|
||||
m_Data += "\n";
|
||||
m_Data += Indent();
|
||||
m_Data += "<";
|
||||
m_Data += name;
|
||||
|
||||
++m_Indent;
|
||||
}
|
||||
@@ -86,7 +89,11 @@ void XMLWriter_File::ElementEnd(const char* name, int type)
|
||||
m_Data += ">";
|
||||
break;
|
||||
case EL_SUBEL:
|
||||
m_Data += "\n" + Indent() + "</" + name += ">";
|
||||
m_Data += "\n";
|
||||
m_Data += Indent();
|
||||
m_Data += "</";
|
||||
m_Data += name;
|
||||
m_Data += ">";
|
||||
break;
|
||||
default:
|
||||
debug_assert(0);
|
||||
@@ -140,7 +147,9 @@ template <> void XMLWriter_File::ElementAttribute<CStr>(const char* name, const
|
||||
debug_assert(m_LastElement && m_LastElement->m_Type == EL_ATTR);
|
||||
m_Data += " ";
|
||||
m_Data += name;
|
||||
m_Data += "=\"" + value + "\"";
|
||||
m_Data += "=\"";
|
||||
m_Data += value;
|
||||
m_Data += "\"";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "BaseEntity.h"
|
||||
#include "Model.h"
|
||||
#include "ObjectEntry.h"
|
||||
#include "SkeletonAnim.h"
|
||||
#include "SkeletonAnimDef.h" // Animation duration
|
||||
#include "Unit.h"
|
||||
#include "ProductionQueue.h"
|
||||
|
||||
Reference in New Issue
Block a user