diff options
| author | claude-bot <[email protected]> | 2026-07-13 12:40:03 +0000 |
|---|---|---|
| committer | claude-bot <[email protected]> | 2026-07-13 12:40:03 +0000 |
| commit | 847962910f0bff071f3bf07c9abb87764fb6cac3 (patch) | |
| tree | ddcd429e134c7fd5f72ddc97ced175de8d66fcd0 /src/base.cpp | |
| download | librw-master.tar.gz librw-master.zip | |
Snapshot for re3/reVC vendoring, per @lzcnt.
Source: https://github.com/aap/librw (master).
Diffstat (limited to 'src/base.cpp')
| -rw-r--r-- | src/base.cpp | 1123 |
1 files changed, 1123 insertions, 0 deletions
diff --git a/src/base.cpp b/src/base.cpp new file mode 100644 index 0000000..3c3ca08 --- /dev/null +++ b/src/base.cpp @@ -0,0 +1,1123 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <math.h> +#include <ctype.h> + +#define PSEP_C '/' +#define PSEP_S "/" +#ifdef __unix__ +#include <sys/types.h> +#include <dirent.h> +#endif + +#include "rwbase.h" +#include "rwerror.h" +#include "rwplg.h" +#include "rwpipeline.h" +#include "rwobjects.h" +#include "rwengine.h" + +namespace rw { + +#define PLUGIN_ID 0 + +int32 version = 0x36003; +int32 build = 0xFFFF; +#ifdef RW_PS2 + int32 platform = PLATFORM_PS2; +#elif RW_WDGL + int32 platform = PLATFORM_WDGL; +#elif RW_GL3 + int32 platform = PLATFORM_GL3; +#elif RW_D3D9 + int32 platform = PLATFORM_D3D9; +#else + int32 platform = PLATFORM_NULL; +#endif +bool32 streamAppendFrames = 0; +char *debugFile = nil; + +static Matrix identMat = { + { 1.0f, 0.0f, 0.0f }, Matrix::IDENTITY|Matrix::TYPEORTHONORMAL, + { 0.0f, 1.0f, 0.0f }, 0, + { 0.0f, 0.0f, 1.0f }, 0, + { 0.0f, 0.0f, 0.0f }, 0 +}; + +// lazy implementation +int +strcmp_ci(const char *s1, const char *s2) +{ + char c1, c2; + for(;;){ + c1 = tolower(*s1); + c2 = tolower(*s2); + if(c1 != c2) + return c1 - c2; + if(c1 == '\0') + return 0; + s1++; + s2++; + } +} + +int +strncmp_ci(const char *s1, const char *s2, int n) +{ + char c1, c2; + while(n--){ + c1 = tolower(*s1); + c2 = tolower(*s2); + if(c1 != c2) + return c1 - c2; + if(c1 == '\0') + return 0; + s1++; + s2++; + } + return 0; +} + +Quat +mult(const Quat &q, const Quat &p) +{ + return makeQuat(q.w*p.w - q.x*p.x - q.y*p.y - q.z*p.z, + q.w*p.x + q.x*p.w + q.y*p.z - q.z*p.y, + q.w*p.y + q.y*p.w + q.z*p.x - q.x*p.z, + q.w*p.z + q.z*p.w + q.x*p.y - q.y*p.x); +} + + +Quat* +Quat::rotate(const V3d *axis, float32 angle, CombineOp op) +{ + Quat rot = rotation(angle, *axis); + switch(op){ + case COMBINEREPLACE: + *this = rot; + break; + case COMBINEPRECONCAT: + *this = mult(*this, rot); + break; + case COMBINEPOSTCONCAT: + *this = mult(rot, *this); + break; + } + return this; +} + +Quat +lerp(const Quat &q, const Quat &p, float32 r) +{ + float32 c; + Quat q1 = q; + c = dot(q1, p); + if(c < 0.0f){ + c = -c; + q1 = negate(q1); + } + return makeQuat(q1.w + r*(p.w - q1.w), + q1.x + r*(p.x - q1.x), + q1.y + r*(p.y - q1.y), + q1.z + r*(p.z - q1.z)); +}; + +Quat +slerp(const Quat &q, const Quat &p, float32 a) +{ + float32 c; + Quat q1 = q; + c = dot(q1, p); + if(c < 0.0f){ + c = -c; + q1 = negate(q1); + } + float32 phi = acosf(c); + if(phi > 0.00001f){ + float32 s = sinf(phi); + return add(scale(q1, sinf((1.0f-a)*phi)/s), + scale(p, sinf(a*phi)/s)); + } + return q1; +} + +// +// V3d +// + +V3d +cross(const V3d &a, const V3d &b) +{ + return makeV3d(a.y*b.z - a.z*b.y, + a.z*b.x - a.x*b.z, + a.x*b.y - a.y*b.x); +} + +void +V3d::transformPoints(V3d *out, const V3d *in, int32 n, const Matrix *m) +{ + int32 i; + V3d tmp; + for(i = 0; i < n; i++){ + tmp.x = in[i].x*m->right.x + in[i].y*m->up.x + in[i].z*m->at.x + m->pos.x; + tmp.y = in[i].x*m->right.y + in[i].y*m->up.y + in[i].z*m->at.y + m->pos.y; + tmp.z = in[i].x*m->right.z + in[i].y*m->up.z + in[i].z*m->at.z + m->pos.z; + out[i] = tmp; + } +} + +void +V3d::transformVectors(V3d *out, const V3d *in, int32 n, const Matrix *m) +{ + int32 i; + V3d tmp; + for(i = 0; i < n; i++){ + tmp.x = in[i].x*m->right.x + in[i].y*m->up.x + in[i].z*m->at.x; + tmp.y = in[i].x*m->right.y + in[i].y*m->up.y + in[i].z*m->at.y; + tmp.z = in[i].x*m->right.z + in[i].y*m->up.z + in[i].z*m->at.z; + out[i] = tmp; + } +} + +// +// RawMatrix +// + +void +RawMatrix::mult(RawMatrix *dst, RawMatrix *src1, RawMatrix *src2) +{ + dst->right.x = src1->right.x*src2->right.x + src1->right.y*src2->up.x + src1->right.z*src2->at.x + src1->rightw*src2->pos.x; + dst->right.y = src1->right.x*src2->right.y + src1->right.y*src2->up.y + src1->right.z*src2->at.y + src1->rightw*src2->pos.y; + dst->right.z = src1->right.x*src2->right.z + src1->right.y*src2->up.z + src1->right.z*src2->at.z + src1->rightw*src2->pos.z; + dst->rightw = src1->right.x*src2->rightw + src1->right.y*src2->upw + src1->right.z*src2->atw + src1->rightw*src2->posw; + dst->up.x = src1->up.x*src2->right.x + src1->up.y*src2->up.x + src1->up.z*src2->at.x + src1->upw*src2->pos.x; + dst->up.y = src1->up.x*src2->right.y + src1->up.y*src2->up.y + src1->up.z*src2->at.y + src1->upw*src2->pos.y; + dst->up.z = src1->up.x*src2->right.z + src1->up.y*src2->up.z + src1->up.z*src2->at.z + src1->upw*src2->pos.z; + dst->upw = src1->up.x*src2->rightw + src1->up.y*src2->upw + src1->up.z*src2->atw + src1->upw*src2->posw; + dst->at.x = src1->at.x*src2->right.x + src1->at.y*src2->up.x + src1->at.z*src2->at.x + src1->atw*src2->pos.x; + dst->at.y = src1->at.x*src2->right.y + src1->at.y*src2->up.y + src1->at.z*src2->at.y + src1->atw*src2->pos.y; + dst->at.z = src1->at.x*src2->right.z + src1->at.y*src2->up.z + src1->at.z*src2->at.z + src1->atw*src2->pos.z; + dst->atw = src1->at.x*src2->rightw + src1->at.y*src2->upw + src1->at.z*src2->atw + src1->atw*src2->posw; + dst->pos.x = src1->pos.x*src2->right.x + src1->pos.y*src2->up.x + src1->pos.z*src2->at.x + src1->posw*src2->pos.x; + dst->pos.y = src1->pos.x*src2->right.y + src1->pos.y*src2->up.y + src1->pos.z*src2->at.y + src1->posw*src2->pos.y; + dst->pos.z = src1->pos.x*src2->right.z + src1->pos.y*src2->up.z + src1->pos.z*src2->at.z + src1->posw*src2->pos.z; + dst->posw = src1->pos.x*src2->rightw + src1->pos.y*src2->upw + src1->pos.z*src2->atw + src1->posw*src2->posw; +} + +void +RawMatrix::transpose(RawMatrix *dst, RawMatrix *src) +{ + dst->right.x = src->right.x; + dst->up.x = src->right.y; + dst->at.x = src->right.z; + dst->pos.x = src->rightw; + dst->right.y = src->up.x; + dst->up.y = src->up.y; + dst->at.y = src->up.z; + dst->pos.y = src->upw; + dst->right.z = src->at.x; + dst->up.z = src->at.y; + dst->at.z = src->at.z; + dst->pos.z = src->atw; + dst->rightw = src->pos.x; + dst->upw = src->pos.y; + dst->atw = src->pos.z; + dst->posw = src->posw; +} + +void +RawMatrix::setIdentity(RawMatrix *dst) +{ + static RawMatrix identity = { + { 1.0f, 0.0f, 0.0f }, 0.0f, + { 0.0f, 1.0f, 0.0f }, 0.0f, + { 0.0f, 0.0f, 1.0f }, 0.0f, + { 0.0f, 0.0f, 0.0f }, 1.0f + }; + *dst = identity; +} + +// +// Matrix +// + +static Matrix::Tolerance matrixDefaultTolerance = { 0.01f, 0.01f, 0.01f }; + +Matrix* +Matrix::create(void) +{ + Matrix *m = (Matrix*)rwMalloc(sizeof(Matrix), MEMDUR_EVENT | ID_MATRIX); + m->setIdentity(); + return m; +} + +void +Matrix::destroy(void) +{ + rwFree(this); +} + +void +Matrix::setIdentity(void) +{ + *this = identMat; +} + +void +Matrix::optimize(Tolerance *tolerance) +{ + bool32 isnormal, isorthogonal, isidentity; + if(tolerance == nil) + tolerance = &matrixDefaultTolerance; + isnormal = normalError() <= tolerance->normal; + isorthogonal = orthogonalError() <= tolerance->orthogonal; + isidentity = isnormal && isorthogonal && identityError() <= tolerance->identity; + if(isnormal) + flags |= TYPENORMAL; + else + flags &= ~TYPENORMAL; + if(isorthogonal) + flags |= TYPEORTHOGONAL; + else + flags &= ~TYPEORTHOGONAL; + if(isidentity) + flags |= IDENTITY; + else + flags &= ~IDENTITY; +} + +Matrix* +Matrix::mult(Matrix *dst, const Matrix *src1, const Matrix *src2) +{ + if(src1->flags & IDENTITY) + *dst = *src2; + else if(src2->flags & IDENTITY) + *dst = *src1; + else{ + mult_(dst, src1, src2); + dst->flags = src1->flags & src2->flags; + } + return dst; +} + +Matrix* +Matrix::invert(Matrix *dst, const Matrix *src) +{ + if(src->flags & IDENTITY) + *dst = *src; + else if((src->flags & TYPEMASK) == TYPEORTHONORMAL) + invertOrthonormal(dst, src); + else + return invertGeneral(dst, src); + return dst; +} + +// transpose the 3x3 submatrix, pos is set to 0 +Matrix* +Matrix::transpose(Matrix *dst, const Matrix *src) +{ + if(src->flags & IDENTITY) + *dst = *src; + dst->right.x = src->right.x; + dst->up.x = src->right.y; + dst->at.x = src->right.z; + dst->right.y = src->up.x; + dst->up.y = src->up.y; + dst->at.y = src->up.z; + dst->right.z = src->at.x; + dst->up.z = src->at.y; + dst->at.z = src->at.z; + dst->pos.x = 0.0; + dst->pos.y = 0.0; + dst->pos.z = 0.0; + return dst; +} + +Matrix* +Matrix::rotate(const V3d *axis, float32 angle, CombineOp op) +{ + Matrix tmp, rot; + makeRotation(&rot, axis, angle); + switch(op){ + case COMBINEREPLACE: + *this = rot; + break; + case COMBINEPRECONCAT: + mult(&tmp, &rot, this); + *this = tmp; + break; + case COMBINEPOSTCONCAT: + mult(&tmp, this, &rot); + *this = tmp; + break; + } + return this; +} + +Matrix* +Matrix::rotate(const Quat &q, CombineOp op) +{ + Matrix tmp, rot; + makeRotation(&rot, q); + switch(op){ + case COMBINEREPLACE: + *this = rot; + break; + case COMBINEPRECONCAT: + mult(&tmp, &rot, this); + *this = tmp; + break; + case COMBINEPOSTCONCAT: + mult(&tmp, this, &rot); + *this = tmp; + break; + } + return this; +} +Matrix* +Matrix::translate(const V3d *translation, CombineOp op) +{ + Matrix tmp; + Matrix trans = identMat; + trans.pos = *translation; + trans.flags &= ~IDENTITY; + switch(op){ + case COMBINEREPLACE: + *this = trans; + break; + case COMBINEPRECONCAT: + mult(&tmp, &trans, this); + *this = tmp; + break; + case COMBINEPOSTCONCAT: + mult(&tmp, this, &trans); + *this = tmp; + break; + } + return this; +} + +Matrix* +Matrix::scale(const V3d *scale, CombineOp op) +{ + Matrix tmp; + Matrix scl = identMat; + scl.right.x = scale->x; + scl.up.y = scale->y; + scl.at.z = scale->z; + scl.flags &= ~IDENTITY; + switch(op){ + case COMBINEREPLACE: + *this = scl; + break; + case COMBINEPRECONCAT: + mult(&tmp, &scl, this); + *this = tmp; + break; + case COMBINEPOSTCONCAT: + mult(&tmp, this, &scl); + *this = tmp; + break; + } + return this; +} + +Matrix* +Matrix::transform(const Matrix *mat, CombineOp op) +{ + Matrix tmp; + switch(op){ + case COMBINEREPLACE: + *this = *mat; + break; + case COMBINEPRECONCAT: + mult(&tmp, mat, this); + *this = tmp; + break; + case COMBINEPOSTCONCAT: + mult(&tmp, this, mat); + *this = tmp; + break; + } + return this; +} + +Quat +Matrix::getRotation(void) +{ + Quat q = { 0.0f, 0.0f, 0.0f, 1.0f }; + float32 tr = right.x + up.y + at.z; + float s; + if(tr > 0.0f){ + s = sqrtf(1.0f + tr) * 2.0f; + q.w = s / 4.0f; + q.x = (up.z - at.y) / s; + q.y = (at.x - right.z) / s; + q.z = (right.y - up.x) / s; + }else if(right.x > up.y && right.x > at.z){ + s = sqrtf(1.0f + right.x - up.y - at.z) * 2.0f; + q.w = (up.z - at.y) / s; + q.x = s / 4.0f; + q.y = (up.x + right.y) / s; + q.z = (at.x + right.z) / s; + }else if(up.y > at.z){ + s = sqrtf(1.0f + up.y - right.x - at.z) * 2.0f; + q.w = (at.x - right.z) / s; + q.x = (up.x + right.y) / s; + q.y = s / 4.0f; + q.z = (at.y + up.z) / s; + }else{ + s = sqrtf(1.0f + at.z - right.x - up.y) * 2.0f; + q.w = (right.y - up.x) / s; + q.x = (at.x + right.z) / s; + q.y = (at.y + up.z) / s; + q.z = s / 4.0f; + } + return q; +} + +void +Matrix::lookAt(const V3d &dir, const V3d &up) +{ + // this->right is really pointing left + this->at = normalize(dir); + this->right = normalize(cross(up, this->at)); + this->up = cross(this->at, this->right); + this->flags = TYPEORTHONORMAL; +} + +/* For a row-major representation, this calculates src1 * src2. + * For column-major src2 * src1. + * i.e. a vector is first xformed by src1, then by src2 + */ +void +Matrix::mult_(Matrix *dst, const Matrix *src1, const Matrix *src2) +{ + dst->right.x = src1->right.x*src2->right.x + src1->right.y*src2->up.x + src1->right.z*src2->at.x; + dst->right.y = src1->right.x*src2->right.y + src1->right.y*src2->up.y + src1->right.z*src2->at.y; + dst->right.z = src1->right.x*src2->right.z + src1->right.y*src2->up.z + src1->right.z*src2->at.z; + dst->up.x = src1->up.x*src2->right.x + src1->up.y*src2->up.x + src1->up.z*src2->at.x; + dst->up.y = src1->up.x*src2->right.y + src1->up.y*src2->up.y + src1->up.z*src2->at.y; + dst->up.z = src1->up.x*src2->right.z + src1->up.y*src2->up.z + src1->up.z*src2->at.z; + dst->at.x = src1->at.x*src2->right.x + src1->at.y*src2->up.x + src1->at.z*src2->at.x; + dst->at.y = src1->at.x*src2->right.y + src1->at.y*src2->up.y + src1->at.z*src2->at.y; + dst->at.z = src1->at.x*src2->right.z + src1->at.y*src2->up.z + src1->at.z*src2->at.z; + dst->pos.x = src1->pos.x*src2->right.x + src1->pos.y*src2->up.x + src1->pos.z*src2->at.x + src2->pos.x; + dst->pos.y = src1->pos.x*src2->right.y + src1->pos.y*src2->up.y + src1->pos.z*src2->at.y + src2->pos.y; + dst->pos.z = src1->pos.x*src2->right.z + src1->pos.y*src2->up.z + src1->pos.z*src2->at.z + src2->pos.z; +} + +void +Matrix::invertOrthonormal(Matrix *dst, const Matrix *src) +{ + dst->right.x = src->right.x; + dst->right.y = src->up.x; + dst->right.z = src->at.x; + dst->up.x = src->right.y; + dst->up.y = src->up.y; + dst->up.z = src->at.y; + dst->at.x = src->right.z; + dst->at.y = src->up.z; + dst->at.z = src->at.z; + dst->pos.x = -(src->pos.x*src->right.x + + src->pos.y*src->right.y + + src->pos.z*src->right.z); + dst->pos.y = -(src->pos.x*src->up.x + + src->pos.y*src->up.y + + src->pos.z*src->up.z); + dst->pos.z = -(src->pos.x*src->at.x + + src->pos.y*src->at.y + + src->pos.z*src->at.z); + dst->flags = TYPEORTHONORMAL; +} + +Matrix* +Matrix::invertGeneral(Matrix *dst, const Matrix *src) +{ + float32 det, invdet; + // calculate a few cofactors + dst->right.x = src->up.y*src->at.z - src->up.z*src->at.y; + dst->right.y = src->at.y*src->right.z - src->at.z*src->right.y; + dst->right.z = src->right.y*src->up.z - src->right.z*src->up.y; + // get the determinant from that + det = src->up.x * dst->right.y + src->at.x * dst->right.z + dst->right.x * src->right.x; + invdet = 1.0; + if(det != 0.0f) + invdet = 1.0f/det; + dst->right.x *= invdet; + dst->right.y *= invdet; + dst->right.z *= invdet; + dst->up.x = invdet * (src->up.z*src->at.x - src->up.x*src->at.z); + dst->up.y = invdet * (src->at.z*src->right.x - src->at.x*src->right.z); + dst->up.z = invdet * (src->right.z*src->up.x - src->right.x*src->up.z); + dst->at.x = invdet * (src->up.x*src->at.y - src->up.y*src->at.x); + dst->at.y = invdet * (src->at.x*src->right.y - src->at.y*src->right.x); + dst->at.z = invdet * (src->right.x*src->up.y - src->right.y*src->up.x); + dst->pos.x = -(src->pos.x*dst->right.x + src->pos.y*dst->up.x + src->pos.z*dst->at.x); + dst->pos.y = -(src->pos.x*dst->right.y + src->pos.y*dst->up.y + src->pos.z*dst->at.y); + dst->pos.z = -(src->pos.x*dst->right.z + src->pos.y*dst->up.z + src->pos.z*dst->at.z); + dst->flags &= ~IDENTITY; + return dst; +} + +void +Matrix::makeRotation(Matrix *dst, const V3d *axis, float32 angle) +{ +// V3d v = normalize(*axis); + float32 len = dot(*axis, *axis); + if(len != 0.0f) len = 1.0f/sqrtf(len); + V3d v = rw::scale(*axis, len); + angle = angle*(float)M_PI/180.0f; + float32 s = sinf(angle); + float32 c = cosf(angle); + float32 t = 1.0f - c; + + dst->right.x = c + v.x*v.x*t; + dst->right.y = v.x*v.y*t + v.z*s; + dst->right.z = v.z*v.x*t - v.y*s; + dst->up.x = v.x*v.y*t - v.z*s; + dst->up.y = c + v.y*v.y*t; + dst->up.z = v.y*v.z*t + v.x*s; + dst->at.x = v.z*v.x*t + v.y*s; + dst->at.y = v.y*v.z*t - v.x*s; + dst->at.z = c + v.z*v.z*t; + dst->pos.x = 0.0; + dst->pos.y = 0.0; + dst->pos.z = 0.0; + dst->flags = TYPEORTHONORMAL; + dst->pad1 = dst->pad2 = dst->pad3 = 0; +} + +/* q must be normalized */ +void +Matrix::makeRotation(Matrix *dst, const Quat &q) +{ + float xx = q.x*q.x; + float yy = q.y*q.y; + float zz = q.z*q.z; + float yz = q.y*q.z; + float zx = q.z*q.x; + float xy = q.x*q.y; + float wx = q.w*q.x; + float wy = q.w*q.y; + float wz = q.w*q.z; + + dst->right.x = 1.0f - 2.0f*(yy + zz); + dst->right.y = 2.0f*(xy + wz); + dst->right.z = 2.0f*(zx - wy); + dst->up.x = 2.0f*(xy - wz); + dst->up.y = 1.0f - 2.0f*(xx + zz); + dst->up.z = 2.0f*(yz + wx); + dst->at.x = 2.0f*(zx + wy); + dst->at.y = 2.0f*(yz - wx); + dst->at.z = 1.0f - 2.0f*(xx + yy); + dst->pos.x = 0.0; + dst->pos.y = 0.0; + dst->pos.z = 0.0; + dst->flags = TYPEORTHONORMAL; + dst->pad1 = dst->pad2 = dst->pad3 = 0; +} + +float32 +Matrix::normalError(void) +{ + float32 x, y, z; + x = dot(right, right) - 1.0f; + y = dot(up, up) - 1.0f; + z = dot(at, at) - 1.0f; + return x*x + y*y + z*z; +} + +float32 +Matrix::orthogonalError(void) +{ + float32 x, y, z; + x = dot(at, up); + y = dot(at, right); + z = dot(up, right); + return x*x + y*y + z*z; +} + +float32 +Matrix::identityError(void) +{ + V3d r = { right.x-1.0f, right.y, right.z }; + V3d u = { up.x, up.y-1.0f, up.z }; + V3d a = { at.x, at.y, at.z-1.0f }; + return dot(r,r) + dot(u,u) + dot(a,a) + dot(pos,pos); +} + +void +correctPathCase(char *filename) +{ +#ifdef __unix__ + DIR *direct; + struct dirent *dirent; + + char *dir, *arg; + char copy[1024], sofar[1024] = "."; + strncpy(copy, filename, 1024); + arg = copy; + // hack for absolute paths + if(filename[0] == '/'){ + sofar[0] = '/'; + sofar[1] = '/'; + sofar[2] = '\0'; + arg++; + } + while((dir = strtok(arg, PSEP_S))){ + arg = nil; + if(direct = opendir(sofar), dir == nil) + return; + while(dirent = readdir(direct), dirent != nil) + if(strncmp_ci(dirent->d_name, dir, 1024) == 0){ + strncat(sofar, PSEP_S, 1024); + strncat(sofar, dirent->d_name, 1024); + break; + } + closedir(direct); + if(dirent == nil) + return; + } + strcpy(filename, sofar+2); +#endif +} + +void +makePath(char *filename) +{ + size_t len = strlen(filename); + for(size_t i = 0; i < len; i++) + if(filename[i] == '/' || filename[i] == '\\') + filename[i] = PSEP_C; +#ifdef __unix__ + correctPathCase(filename); +#endif +} + +void +memNative32_func(void *data, uint32 size) +{ + uint8 *bytes = (uint8*)data; + uint32 *words = (uint32*)data; + size >>= 2; + while(size--){ + *words++ = (uint32)bytes[0] | (uint32)bytes[1]<<8 | + (uint32)bytes[2]<<16 | (uint32)bytes[3]<<24; + bytes += 4; + } +} + +void +memNative16_func(void *data, uint32 size) +{ + uint8 *bytes = (uint8*)data; + uint16 *words = (uint16*)data; + size >>= 1; + while(size--){ + *words++ = (uint16)bytes[0] | (uint16)bytes[1]<<8; + bytes += 2; + } +} + +void +memLittle32_func(void *data, uint32 size) +{ + uint32 w; + uint8 *bytes = (uint8*)data; + uint32 *words = (uint32*)data; + size >>= 2; + while(size--){ + w = *words++; + *bytes++ = w; + *bytes++ = w >> 8; + *bytes++ = w >> 16; + *bytes++ = w >> 24; + } +} + +void +memLittle16_func(void *data, uint32 size) +{ + uint16 w; + uint8 *bytes = (uint8*)data; + uint16 *words = (uint16*)data; + size >>= 1; + while(size--){ + w = *words++; + *bytes++ = (uint8)w; + *bytes++ = w >> 8; + } +} + +uint32 +Stream::write32(const void *data, uint32 length) +{ +#ifdef BIGENDIAN + uint8 *src = (uint8*)data; + uint32 buf[256]; + int32 n, len; + for(len = length >>= 2; len > 0; len -= 256){ + n = len < 256 ? len : 256; + memcpy(buf, src, n*4); + memLittle32(buf, n*4); + write8(buf, n*4); + src += n*4; + } + return length; +#else + return write8(data, length); +#endif +} + +uint32 +Stream::write16(const void *data, uint32 length) +{ +#ifdef BIGENDIAN + uint8 *src = (uint8*)data; + uint16 buf[256]; + int32 n, len; + for(len = length >>= 1; len > 0; len -= 256){ + n = len < 256 ? len : 256; + memcpy(buf, src, n*2); + memLittle16(buf, n*2); + write8(buf, n*2); + src += n*2; + } + return length; +#else + return write8(data, length); +#endif +} + +uint32 +Stream::read32(void *data, uint32 length) +{ + uint32 ret; + ret = read8(data, length); + memNative32(data, length); + return ret; +} + +uint32 +Stream::read16(void *data, uint32 length) +{ + uint32 ret; + ret = read8(data, length); + memNative16(data, length); + return ret; +} + +int32 +Stream::writeI8(int8 val) +{ + return write8(&val, sizeof(int8)); +} + +int32 +Stream::writeU8(uint8 val) +{ + return write8(&val, sizeof(uint8)); +} + +int32 +Stream::writeI16(int16 val) +{ + return write16(&val, sizeof(int16)); +} + +int32 +Stream::writeU16(uint16 val) +{ + return write16(&val, sizeof(uint16)); +} + +int32 +Stream::writeI32(int32 val) +{ + return write32(&val, sizeof(int32)); +} + +int32 +Stream::writeU32(uint32 val) +{ + return write32(&val, sizeof(uint32)); +} + +int32 +Stream::writeF32(float32 val) +{ + return write32(&val, sizeof(float32)); +} + +int8 +Stream::readI8(void) +{ + int8 tmp; + read8(&tmp, sizeof(int8)); + return tmp; +} + +uint8 +Stream::readU8(void) +{ + uint8 tmp; + read8(&tmp, sizeof(uint8)); + return tmp; +} + +int16 +Stream::readI16(void) +{ + int16 tmp; + read16(&tmp, sizeof(int16)); + return tmp; +} + +uint16 +Stream::readU16(void) +{ + uint16 tmp; + read16(&tmp, sizeof(uint16)); + return tmp; +} + +int32 +Stream::readI32(void) +{ + int32 tmp; + read32(&tmp, sizeof(int32)); + return tmp; +} + +uint32 +Stream::readU32(void) +{ + uint32 tmp; + read32(&tmp, sizeof(uint32)); + return tmp; +} + +float32 +Stream::readF32(void) +{ + float32 tmp; + read32(&tmp, sizeof(float32)); + return tmp; +} + + + +void +StreamMemory::close(void) +{ +} + +uint32 +StreamMemory::write8(const void *data, uint32 len) +{ + if(this->eof()) + return 0; + uint32 l = len; + if(this->position+l > this->length){ + if(this->position+l > this->capacity) + l = this->capacity-this->position; + this->length = this->position+l; + } + memcpy(&this->data[this->position], data, l); + this->position += l; + if(len != l) + this->position = S_EOF; + return l; +} + +uint32 +StreamMemory::read8(void *data, uint32 len) +{ + if(this->eof()) + return 0; + uint32 l = len; + if(this->position+l > this->length) + l = this->length-this->position; + memcpy(data, &this->data[this->position], l); + this->position += l; + if(len != l) + this->position = S_EOF; + return l; +} + +void +StreamMemory::seek(int32 offset, int32 whence) +{ + if(whence == 0) + this->position = offset; + else if(whence == 1) + this->position += offset; + else + this->position = this->length-offset; + if(this->position > this->length){ + // TODO: ideally this would depend on the mode + if(this->position > this->capacity) + this->position = S_EOF; + else + this->length = this->position; + } +} + +uint32 +StreamMemory::tell(void) +{ + return this->position; +} + +bool +StreamMemory::eof(void) +{ + return this->position == S_EOF; +} + +StreamMemory* +StreamMemory::open(uint8 *data, uint32 length, uint32 capacity) +{ + this->data = data; + this->capacity = capacity; + this->length = length; + if(this->capacity < this->length) + this->capacity = this->length; + this->position = 0; + return this; +} + +uint32 +StreamMemory::getLength(void) +{ + return this->length; +} + + +StreamFile* +StreamFile::open(const char *path, const char *mode) +{ + assert(this->file == nil); + this->file = engine->filefuncs.rwfopen(path, mode); + if(this->file == nil){ + RWERROR((ERR_FILE, path)); + return nil; + } + return this; +} + +void +StreamFile::close(void) +{ + assert(this->file); + engine->filefuncs.rwfclose(this->file); + this->file = nil; +} + +uint32 +StreamFile::write8(const void *data, uint32 length) +{ + return (uint32)engine->filefuncs.rwfwrite(data, 1, length, this->file); +} + +uint32 +StreamFile::read8(void *data, uint32 length) +{ + return (uint32)engine->filefuncs.rwfread(data, 1, length, this->file); +} + +void +StreamFile::seek(int32 offset, int32 whence) +{ + engine->filefuncs.rwfseek(this->file, offset, whence); +} + +uint32 +StreamFile::tell(void) +{ + return engine->filefuncs.rwftell(this->file); +} + +bool +StreamFile::eof(void) +{ + return engine->filefuncs.rwfeof(this->file) != 0; +} + +bool +writeChunkHeader(Stream *s, int32 type, int32 size) +{ + struct { + int32 type, size; + uint32 id; + } buf = { type, size, libraryIDPack(version, build) }; + s->write32(&buf, 12); + return true; +} + +bool +readChunkHeaderInfo(Stream *s, ChunkHeaderInfo *header) +{ + struct { + int32 type, size; + uint32 id; + } buf; + s->read32(&buf, 12); + if(s->eof()) + return false; + assert(header != nil); + header->type = buf.type; + header->length = buf.size; + header->version = libraryIDUnpackVersion(buf.id); + header->build = libraryIDUnpackBuild(buf.id); + return true; +} + +bool +findChunk(Stream *s, uint32 type, uint32 *length, uint32 *version) +{ + ChunkHeaderInfo header; + while(readChunkHeaderInfo(s, &header)){ + if(header.type == ID_NAOBJECT) + return false; + if(header.type == type){ + if(length) + *length = header.length; + if(version) + *version = header.version; + return true; + } + s->seek(header.length); + } + return false; +} + +int32 +findPointer(void *p, void **list, int32 num) +{ + int i; + for(i = 0; i < num; i++) + if(list[i] == p) + return i; + return -1; +} + +uint8* +getFileContents(const char *name, uint32 *len) +{ + void *cf = engine->filefuncs.rwfopen(name, "rb"); + if(cf == nil) + return nil; + engine->filefuncs.rwfseek(cf, 0, SEEK_END); + *len = engine->filefuncs.rwftell(cf); + engine->filefuncs.rwfseek(cf, 0, SEEK_SET); + uint8 *data = rwNewT(uint8, *len, MEMDUR_EVENT); + engine->filefuncs.rwfread(data, 1, *len, cf); + engine->filefuncs.rwfclose(cf); + return data; +} + +} |
