/* Relay -- a tool to record and play Quake2 demos Copyright (C) 2000 Conor Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Conor Davis cedavis@planetquake.com */ #include #include #include "shared.h" #include "block.h" #include "endian.h" #include "q2defines.h" // // generic block functions // void BlockInit(block_t *block, char *buffer, size_t size) { block->buffer = buffer; block->size = size; block->readoffset = 0; block->writeoffset = 0; block->writelen = 0; block->readoverflow = false; block->writeoverflow = false; } void BlockRewind(block_t *block) { block->readoffset = 0; block->writeoffset = 0; block->writelen = 0; block->readoverflow = false; block->writeoverflow = false; } void BlockRewindRead(block_t *block) { block->readoffset = 0; block->readoverflow = false; } qboolean ReadOverflow(block_t *block) { return block->readoverflow; } qboolean WriteOverflow(block_t *block) { return block->writeoverflow; } // CheckRead // Determines whether it is safe to read len bytes // from block static qboolean CheckRead(block_t *block, size_t len) { if (block->readoffset + len > block->writeoffset) { block->readoverflow = true; return false; } return true; } // CheckWrite // Determines whether it is safe to write len bytes // to block static qboolean CheckWrite(block_t *block, size_t len) { block->writelen += len; if (block->writeoffset + len > block->size) { block->writeoverflow = true; return false; } return true; } const char *BlockRead(block_t *block, char *buffer, size_t len) { if (!CheckRead(block, len)) return NULL; if (buffer) memcpy(buffer, block->buffer + block->readoffset, len); block->readoffset += len; return block->buffer + block->readoffset - len; } void BlockWrite(block_t *block, const char *buffer, size_t len) { if (!CheckWrite(block, len)) return; memcpy(block->buffer + block->writeoffset, buffer, len); block->writeoffset += len; } const char *BlockCopy(block_t *dest, block_t *src, size_t len) { if (!CheckRead(src, len)) return NULL; if (!CheckWrite(dest, len)) return NULL; memcpy(dest->buffer + dest->writeoffset, src->buffer + src->readoffset, len); src->readoffset += len; dest->writeoffset += len; return dest->buffer + dest->writeoffset - len; } // // low-level read/write functions // char ReadChar(block_t *block) { char a; if (!CheckRead(block, 1)) return 0; a = *(char *)(block->buffer + block->readoffset); block->readoffset++; return a; } void WriteChar(block_t *block, char a) { if (!CheckWrite(block, 1)) return; *(char *)(block->buffer + block->writeoffset) = a; block->writeoffset++; } unsigned char ReadByte(block_t *block) { unsigned char a; if (!CheckRead(block, 1)) return 0; a = *(unsigned char *)(block->buffer + block->readoffset); block->readoffset++; return a; } void WriteByte(block_t *block, unsigned char a) { if (!CheckWrite(block, 1)) return; *(unsigned char *)(block->buffer + block->writeoffset) = a; block->writeoffset++; } short ReadShort(block_t *block) { short a; if (!CheckRead(block, 2)) return 0; a = *(short *)(block->buffer + block->readoffset); block->readoffset += 2; return LittleShort(a); } void WriteShort(block_t *block, short a) { if (!CheckWrite(block, 2)) return; *(short *)(block->buffer + block->writeoffset) = LittleShort(a); block->writeoffset += 2; } long ReadLong(block_t *block) { long a; if (!CheckRead(block, 4)) return 0; a = *(long *)(block->buffer + block->readoffset); block->readoffset += 4; return LittleLong(a); } void WriteLong(block_t *block, long a) { if (!CheckWrite(block, 4)) return; *(long *)(block->buffer + block->writeoffset) = LittleLong(a); block->writeoffset += 4; } unsigned long ReadULong(block_t *block) { unsigned long a; if (!CheckRead(block, 4)) return 0; a = *(unsigned long *)(block->buffer + block->readoffset); block->readoffset += 4; return LittleLong(a); } void WriteULong(block_t *block, unsigned long a) { if (!CheckWrite(block, 4)) return; *(unsigned long *)(block->buffer + block->writeoffset) = LittleLong(a); block->writeoffset += 4; } const char *ReadString(block_t *block) { char *start; start = block->buffer + block->readoffset; while (ReadChar(block)) ; if (ReadOverflow(block)) return ""; return start; } void WriteString(block_t *block, const char *string) { size_t len; len = strlen(string) + 1; if (!CheckWrite(block, len)) return; strcpy(block->buffer + block->writeoffset, string); block->writeoffset += len; } // // higher-level functions that call // the above functions // float ReadFloat(block_t *block) { union {int l; float f;} a; a.l = ReadLong(block); return a.f; } float ReadAngle(block_t *block) { return (float)ReadChar(block) / 256 * 360; } void WriteAngle(block_t *block, float a) { WriteChar(block, (char)(a * 256 / 360)); } float ReadAngle16(block_t *block) { return (float)ReadShort(block) / 65536 * 360; } void WriteAngle16(block_t *block, float a) { WriteShort(block, (short)(a * 65535 / 360)); } float ReadCoord(block_t *block) { return (float)ReadShort(block) * 0.125F; } void WriteCoord(block_t *block, float a) { WriteShort(block, (short)(a * 8)); } float *ReadPosition(block_t *block, float *vec) { vec[0] = ReadCoord(block); vec[1] = ReadCoord(block); vec[2] = ReadCoord(block); return vec; } void WritePosition(block_t *block, const float *vec) { WriteCoord(block, vec[0]); WriteCoord(block, vec[1]); WriteCoord(block, vec[2]); } short *ReadShortPosition(block_t *block, short *vec) { vec[0] = ReadShort(block); vec[1] = ReadShort(block); vec[2] = ReadShort(block); return vec; } void WriteShortPosition(block_t *block, const short *vec) { WriteShort(block, vec[0]); WriteShort(block, vec[1]); WriteShort(block, vec[2]); } #define DM2_NUMVERTEXNORMALS 162 float avertexnormals[3*DM2_NUMVERTEXNORMALS] = { -0.525731027, 0, 0.850651026, -0.442862988, 0.238856003, 0.864188015, -0.295242012, 0, 0.955422997, -0.309017003, 0.5, 0.809017003, -0.162459999, 0.26286599, 0.951056004, 0, 0, 1, 0, 0.850651026, 0.525731027, -0.147621006, 0.71656698, 0.681717992, 0.147621006, 0.71656698, 0.681717992, 0, 0.525731027, 0.850651026, 0.309017003, 0.5, 0.809017003, 0.525731027, 0, 0.850651026, 0.295242012, 0, 0.955422997, 0.442862988, 0.238856003, 0.864188015, 0.162459999, 0.26286599, 0.951056004, -0.681717992, 0.147621006, 0.71656698, -0.809017003, 0.309017003, 0.5, -0.587785006, 0.425325006, 0.688190997, -0.850651026, 0.525731027, 0, -0.864188015, 0.442862988, 0.238856003, -0.71656698, 0.681717992, 0.147621006, -0.688190997, 0.587785006, 0.425325006, -0.5, 0.809017003, 0.309017003, -0.238856003, 0.864188015, 0.442862988, -0.425325006, 0.688190997, 0.587785006, -0.71656698, 0.681717992, -0.147621006, -0.5, 0.809017003, -0.309017003, -0.525731027, 0.850651026, 0, 0, 0.850651026, -0.525731027, -0.238856003, 0.864188015, -0.442862988, 0, 0.955422997, -0.295242012, -0.26286599, 0.951056004, -0.162459999, 0, 1, 0, 0, 0.955422997, 0.295242012, -0.26286599, 0.951056004, 0.162459999, 0.238856003, 0.864188015, 0.442862988, 0.26286599, 0.951056004, 0.162459999, 0.5, 0.809017003, 0.309017003, 0.238856003, 0.864188015, -0.442862988, 0.26286599, 0.951056004, -0.162459999, 0.5, 0.809017003, -0.309017003, 0.850651026, 0.525731027, 0, 0.71656698, 0.681717992, 0.147621006, 0.71656698, 0.681717992, -0.147621006, 0.525731027, 0.850651026, 0, 0.425325006, 0.688190997, 0.587785006, 0.864188015, 0.442862988, 0.238856003, 0.688190997, 0.587785006, 0.425325006, 0.809017003, 0.309017003, 0.5, 0.681717992, 0.147621006, 0.71656698, 0.587785006, 0.425325006, 0.688190997, 0.955422997, 0.295242012, 0, 1, 0, 0, 0.951056004, 0.162459999, 0.26286599, 0.850651026, -0.525731027, 0, 0.955422997, -0.295242012, 0, 0.864188015, -0.442862988, 0.238856003, 0.951056004, -0.162459999, 0.26286599, 0.809017003, -0.309017003, 0.5, 0.681717992, -0.147621006, 0.71656698, 0.850651026, 0, 0.525731027, 0.864188015, 0.442862988, -0.238856003, 0.809017003, 0.309017003, -0.5, 0.951056004, 0.162459999, -0.26286599, 0.525731027, 0, -0.850651026, 0.681717992, 0.147621006, -0.71656698, 0.681717992, -0.147621006, -0.71656698, 0.850651026, 0, -0.525731027, 0.809017003, -0.309017003, -0.5, 0.864188015, -0.442862988, -0.238856003, 0.951056004, -0.162459999, -0.26286599, 0.147621006, 0.71656698, -0.681717992, 0.309017003, 0.5, -0.809017003, 0.425325006, 0.688190997, -0.587785006, 0.442862988, 0.238856003, -0.864188015, 0.587785006, 0.425325006, -0.688190997, 0.688190997, 0.587785006, -0.425325006, -0.147621006, 0.71656698, -0.681717992, -0.309017003, 0.5, -0.809017003, 0, 0.525731027, -0.850651026, -0.525731027, 0, -0.850651026, -0.442862988, 0.238856003, -0.864188015, -0.295242012, 0, -0.955422997, -0.162459999, 0.26286599, -0.951056004, 0, 0, -1, 0.295242012, 0, -0.955422997, 0.162459999, 0.26286599, -0.951056004, -0.442862988, -0.238856003, -0.864188015, -0.309017003, -0.5, -0.809017003, -0.162459999, -0.26286599, -0.951056004, 0, -0.850651026, -0.525731027, -0.147621006, -0.71656698, -0.681717992, 0.147621006, -0.71656698, -0.681717992, 0, -0.525731027, -0.850651026, 0.309017003, -0.5, -0.809017003, 0.442862988, -0.238856003, -0.864188015, 0.162459999, -0.26286599, -0.951056004, 0.238856003, -0.864188015, -0.442862988, 0.5, -0.809017003, -0.309017003, 0.425325006, -0.688190997, -0.587785006, 0.71656698, -0.681717992, -0.147621006, 0.688190997, -0.587785006, -0.425325006, 0.587785006, -0.425325006, -0.688190997, 0, -0.955422997, -0.295242012, 0, -1, 0, 0.26286599, -0.951056004, -0.162459999, 0, -0.850651026, 0.525731027, 0, -0.955422997, 0.295242012, 0.238856003, -0.864188015, 0.442862988, 0.26286599, -0.951056004, 0.162459999, 0.5, -0.809017003, 0.309017003, 0.71656698, -0.681717992, 0.147621006, 0.525731027, -0.850651026, 0, -0.238856003, -0.864188015, -0.442862988, -0.5, -0.809017003, -0.309017003, -0.26286599, -0.951056004, -0.162459999, -0.850651026, -0.525731027, 0, -0.71656698, -0.681717992, -0.147621006, -0.71656698, -0.681717992, 0.147621006, -0.525731027, -0.850651026, 0, -0.5, -0.809017003, 0.309017003, -0.238856003, -0.864188015, 0.442862988, -0.26286599, -0.951056004, 0.162459999, -0.864188015, -0.442862988, 0.238856003, -0.809017003, -0.309017003, 0.5, -0.688190997, -0.587785006, 0.425325006, -0.681717992, -0.147621006, 0.71656698, -0.442862988, -0.238856003, 0.864188015, -0.587785006, -0.425325006, 0.688190997, -0.309017003, -0.5, 0.809017003, -0.147621006, -0.71656698, 0.681717992, -0.425325006, -0.688190997, 0.587785006, -0.162459999, -0.26286599, 0.951056004, 0.442862988, -0.238856003, 0.864188015, 0.162459999, -0.26286599, 0.951056004, 0.309017003, -0.5, 0.809017003, 0.147621006, -0.71656698, 0.681717992, 0, -0.525731027, 0.850651026, 0.425325006, -0.688190997, 0.587785006, 0.587785006, -0.425325006, 0.688190997, 0.688190997, -0.587785006, 0.425325006, -0.955422997, 0.295242012, 0, -0.951056004, 0.162459999, 0.26286599, -1, 0, 0, -0.850651026, 0, 0.525731027, -0.955422997, -0.295242012, 0, -0.951056004, -0.162459999, 0.26286599, -0.864188015, 0.442862988, -0.238856003, -0.951056004, 0.162459999, -0.26286599, -0.809017003, 0.309017003, -0.5, -0.864188015, -0.442862988, -0.238856003, -0.951056004, -0.162459999, -0.26286599, -0.809017003, -0.309017003, -0.5, -0.681717992, 0.147621006, -0.71656698, -0.681717992, -0.147621006, -0.71656698, -0.850651026, 0, -0.525731027, -0.688190997, 0.587785006, -0.425325006, -0.587785006, 0.425325006, -0.688190997, -0.425325006, 0.688190997, -0.587785006, -0.425325006, -0.688190997, -0.587785006, -0.587785006, -0.425325006, -0.688190997, -0.688190997, -0.587785006, -0.425325006, }; float *ReadDir(block_t *block, float *a) { int code; code = ReadByte(block); if (code >= DM2_NUMVERTEXNORMALS) assert(0); a[0] = avertexnormals[3 * code + 0]; a[1] = avertexnormals[3 * code + 1]; a[2] = avertexnormals[3 * code + 2]; return a; } void WriteDir(block_t *block, const float *a) { int j, maxdotindex; float dot, maxdot; maxdot = -999999.0; maxdotindex = -1; for (j = 0; j < DM2_NUMVERTEXNORMALS; j++) { dot = avertexnormals[3*j + 0] * a[0] + avertexnormals[3*j + 1] * a[1] + avertexnormals[3*j + 2] * a[2]; if (dot > maxdot) { maxdot = dot; maxdotindex = j; } } WriteByte(block, (byte)maxdotindex); } float ReadBlend(block_t *block) { return (float)ReadByte(block) / 255; } void WriteBlend(block_t *block, float a) { WriteByte(block, (byte)(a * 255)); } float *ReadBlendVec(block_t *block, float *a) { a[0] = ReadBlend(block); a[1] = ReadBlend(block); a[2] = ReadBlend(block); a[3] = ReadBlend(block); return a; } void WriteBlendVec(block_t *block, const float *a) { WriteBlend(block, a[0]); WriteBlend(block, a[1]); WriteBlend(block, a[2]); WriteBlend(block, a[3]); } float ReadOffset(block_t *block) { return (float)ReadChar(block) * 0.25F; } void WriteOffset(block_t *block, float a) { WriteChar(block, (char)(a * 4)); } float *ReadOffsetVec(block_t *block, float *a) { a[0] = ReadOffset(block); a[1] = ReadOffset(block); a[2] = ReadOffset(block); return a; } void WriteOffsetVec(block_t *block, const float *a) { WriteOffset(block, a[0]); WriteOffset(block, a[1]); WriteOffset(block, a[2]); }