diff --git a/source/graphics/Model.cpp b/source/graphics/Model.cpp index afc411db94..60e401c2ea 100755 --- a/source/graphics/Model.cpp +++ b/source/graphics/Model.cpp @@ -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;iSetFlags(m_Flags); for (uint i=0;iAddProp(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; } diff --git a/source/graphics/Model.h b/source/graphics/Model.h index d21290ac7f..d9673a9083 100755 --- a/source/graphics/Model.h +++ b/source/graphics/Model.h @@ -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 diff --git a/source/graphics/ObjectEntry.cpp b/source/graphics/ObjectEntry.cpp index a31a4cdc58..2f6f245832 100755 --- a/source/graphics/ObjectEntry.cpp +++ b/source/graphics/ObjectEntry.cpp @@ -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 >& 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 diff --git a/source/graphics/ObjectEntry.h b/source/graphics/ObjectEntry.h index 2d286acf09..e09b3ff5e1 100755 --- a/source/graphics/ObjectEntry.h +++ b/source/graphics/ObjectEntry.h @@ -3,13 +3,12 @@ class CModel; class CSkeletonAnim; +class CObjectBase; struct SPropPoint; #include #include -#include #include "CStr.h" -#include "ObjectBase.h" #include "Overlay.h" class CObjectEntry diff --git a/source/graphics/Unit.cpp b/source/graphics/Unit.cpp index aecd76b721..dfcd271491 100644 --- a/source/graphics/Unit.cpp +++ b/source/graphics/Unit.cpp @@ -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& 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& props = model->GetProps(); + for (std::vector::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) diff --git a/source/graphics/Unit.h b/source/graphics/Unit.h index 20412e4f26..678a7a9a79 100755 --- a/source/graphics/Unit.h +++ b/source/graphics/Unit.h @@ -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, diff --git a/source/lib/res/graphics/tex.cpp b/source/lib/res/graphics/tex.cpp index bf82704f1c..30959133fc 100755 --- a/source/lib/res/graphics/tex.cpp +++ b/source/lib/res/graphics/tex.cpp @@ -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 diff --git a/source/lib/res/graphics/tex_bmp.cpp b/source/lib/res/graphics/tex_bmp.cpp index 686a2d879e..729a5c6dc3 100644 --- a/source/lib/res/graphics/tex_bmp.cpp +++ b/source/lib/res/graphics/tex_bmp.cpp @@ -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; } diff --git a/source/lib/res/graphics/tex_dds.cpp b/source/lib/res/graphics/tex_dds.cpp index 6f673c39c3..e04539456e 100644 --- a/source/lib/res/graphics/tex_dds.cpp +++ b/source/lib/res/graphics/tex_dds.cpp @@ -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; } diff --git a/source/lib/res/graphics/tex_jpg.cpp b/source/lib/res/graphics/tex_jpg.cpp index 93f7ec5a37..b86f16fb17 100644 --- a/source/lib/res/graphics/tex_jpg.cpp +++ b/source/lib/res/graphics/tex_jpg.cpp @@ -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 - +#include + #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. -* -* -*/ -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. +* +* +*/ +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; } diff --git a/source/lib/res/graphics/tex_png.cpp b/source/lib/res/graphics/tex_png.cpp index cde75c3c6c..b51eb4739b 100644 --- a/source/lib/res/graphics/tex_png.cpp +++ b/source/lib/res/graphics/tex_png.cpp @@ -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; } diff --git a/source/lib/res/graphics/tex_tga.cpp b/source/lib/res/graphics/tex_tga.cpp index e1368aa77f..64f862b804 100644 --- a/source/lib/res/graphics/tex_tga.cpp +++ b/source/lib/res/graphics/tex_tga.cpp @@ -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; } diff --git a/source/ps/XML/XMLWriter.cpp b/source/ps/XML/XMLWriter.cpp index ad8b1a6bc2..6d554195b3 100644 --- a/source/ps/XML/XMLWriter.cpp +++ b/source/ps/XML/XMLWriter.cpp @@ -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() + ""; + m_Data += "\n"; + m_Data += Indent(); + m_Data += ""; break; default: debug_assert(0); @@ -140,7 +147,9 @@ template <> void XMLWriter_File::ElementAttribute(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 += "\""; } } diff --git a/source/simulation/EntityStateProcessing.cpp b/source/simulation/EntityStateProcessing.cpp index be68eb1534..8294cdc4b5 100755 --- a/source/simulation/EntityStateProcessing.cpp +++ b/source/simulation/EntityStateProcessing.cpp @@ -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"