/** * @file patch_code.cpp * @brief Encode patch DCT data into bitcode. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llmath.h" //#include "vmath.h" #include "v3math.h" #include "patch_dct.h" #include "patch_code.h" #include "llbitpack.h" U32 gPatchSize, gWordBits; void init_patch_coding(LLBitPack &bitpack) { bitpack.resetBitPacking(); } void code_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp) { #ifdef LL_BIG_ENDIAN U8 *stride = (U8 *)&gopp->stride; bitpack.bitPack(&(stride[1]), 8); bitpack.bitPack(&(stride[0]), 8); #else bitpack.bitPack((U8 *)&gopp->stride, 16); #endif bitpack.bitPack((U8 *)&gopp->patch_size, 8); bitpack.bitPack((U8 *)&gopp->layer_type, 8); gPatchSize = gopp->patch_size; } void code_patch_header(LLBitPack &bitpack, LLPatchHeader *ph, S32 *patch) { S32 i, j, temp, patch_size = gPatchSize, wbits = (ph->quant_wbits & 0xf) + 2; U32 max_wbits = wbits + 5, min_wbits = wbits>>1; wbits = min_wbits; for (i = 0; i < (int) patch_size*patch_size; i++) { temp = patch[i]; if (temp) { if (temp < 0) temp *= -1; for (j = max_wbits; j > (int) min_wbits; j--) { if (temp & (1<<j)) { if (j > wbits) wbits = j; break; } } } } wbits += 1; ph->quant_wbits &= 0xf0; if ( (wbits > 17) ||(wbits < 2)) { LL_ERRS() << "Bits needed per word in code_patch_header out of legal range. Adjust compression quatization." << LL_ENDL; } ph->quant_wbits |= (wbits - 2); bitpack.bitPack((U8 *)&ph->quant_wbits, 8); #ifdef LL_BIG_ENDIAN U8 *offset = (U8 *)&ph->dc_offset; bitpack.bitPack(&(offset[3]), 8); bitpack.bitPack(&(offset[2]), 8); bitpack.bitPack(&(offset[1]), 8); bitpack.bitPack(&(offset[0]), 8); #else bitpack.bitPack((U8 *)&ph->dc_offset, 32); #endif #ifdef LL_BIG_ENDIAN U8 *range = (U8 *)&ph->range; bitpack.bitPack(&(range[1]), 8); bitpack.bitPack(&(range[0]), 8); #else bitpack.bitPack((U8 *)&ph->range, 16); #endif #ifdef LL_BIG_ENDIAN U8 *ids = (U8 *)&ph->patchids; bitpack.bitPack(&(ids[1]), 8); bitpack.bitPack(&(ids[0]), 2); #else bitpack.bitPack((U8 *)&ph->patchids, 10); #endif gWordBits = wbits; } void code_end_of_data(LLBitPack &bitpack) { bitpack.bitPack((U8 *)&END_OF_PATCHES, 8); } void code_patch(LLBitPack &bitpack, S32 *patch, S32 postquant) { S32 i, j, patch_size = gPatchSize, wbits = gWordBits; S32 temp; BOOL b_eob; if ( (postquant > patch_size*patch_size) ||(postquant < 0)) { LL_ERRS() << "Bad postquant in code_patch!" << LL_ENDL; } if (postquant) patch[patch_size*patch_size - postquant] = 0; for (i = 0; i < patch_size*patch_size; i++) { b_eob = FALSE; temp = patch[i]; if (!temp) { b_eob = TRUE; for (j = i; j < patch_size*patch_size - postquant; j++) { if (patch[j]) { b_eob = FALSE; break; } } if (b_eob) { bitpack.bitPack((U8 *)&ZERO_EOB, 2); return; } else { bitpack.bitPack((U8 *)&ZERO_CODE, 1); } } else { if (temp < 0) { temp *= -1; if (temp > (1<<wbits)) { temp = (1<<wbits); // printf("patch quatization exceeding allowable bits!"); } bitpack.bitPack((U8 *)&NEGATIVE_VALUE, 3); bitpack.bitPack((U8 *)&temp, wbits); } else { if (temp > (1<<wbits)) { temp = (1<<wbits); // printf("patch quatization exceeding allowable bits!"); } bitpack.bitPack((U8 *)&POSITIVE_VALUE, 3); bitpack.bitPack((U8 *)&temp, wbits); } } } } void end_patch_coding(LLBitPack &bitpack) { bitpack.flushBitPack(); } void init_patch_decoding(LLBitPack &bitpack) { bitpack.resetBitPacking(); } void decode_patch_group_header(LLBitPack &bitpack, LLGroupHeader *gopp) { U16 retvalu16; retvalu16 = 0; #ifdef LL_BIG_ENDIAN U8 *ret = (U8 *)&retvalu16; bitpack.bitUnpack(&(ret[1]), 8); bitpack.bitUnpack(&(ret[0]), 8); #else bitpack.bitUnpack((U8 *)&retvalu16, 16); #endif gopp->stride = retvalu16; U8 retvalu8 = 0; bitpack.bitUnpack(&retvalu8, 8); gopp->patch_size = retvalu8; retvalu8 = 0; bitpack.bitUnpack(&retvalu8, 8); gopp->layer_type = retvalu8; gPatchSize = gopp->patch_size; } void decode_patch_header(LLBitPack &bitpack, LLPatchHeader *ph) { U8 retvalu8; retvalu8 = 0; bitpack.bitUnpack(&retvalu8, 8); ph->quant_wbits = retvalu8; if (END_OF_PATCHES == ph->quant_wbits) { // End of data, blitz the rest. ph->dc_offset = 0; ph->range = 0; ph->patchids = 0; return; } U32 retvalu32 = 0; #ifdef LL_BIG_ENDIAN U8 *ret = (U8 *)&retvalu32; bitpack.bitUnpack(&(ret[3]), 8); bitpack.bitUnpack(&(ret[2]), 8); bitpack.bitUnpack(&(ret[1]), 8); bitpack.bitUnpack(&(ret[0]), 8); #else bitpack.bitUnpack((U8 *)&retvalu32, 32); #endif ph->dc_offset = *(F32 *)&retvalu32; U16 retvalu16 = 0; #ifdef LL_BIG_ENDIAN ret = (U8 *)&retvalu16; bitpack.bitUnpack(&(ret[1]), 8); bitpack.bitUnpack(&(ret[0]), 8); #else bitpack.bitUnpack((U8 *)&retvalu16, 16); #endif ph->range = retvalu16; retvalu16 = 0; #ifdef LL_BIG_ENDIAN ret = (U8 *)&retvalu16; bitpack.bitUnpack(&(ret[1]), 8); bitpack.bitUnpack(&(ret[0]), 2); #else bitpack.bitUnpack((U8 *)&retvalu16, 10); #endif ph->patchids = retvalu16; gWordBits = (ph->quant_wbits & 0xf) + 2; } void decode_patch(LLBitPack &bitpack, S32 *patches) { #ifdef LL_BIG_ENDIAN S32 i, j, patch_size = gPatchSize, wbits = gWordBits; U8 tempu8; U16 tempu16; U32 tempu32; for (i = 0; i < patch_size*patch_size; i++) { bitpack.bitUnpack((U8 *)&tempu8, 1); if (tempu8) { // either 0 EOB or Value bitpack.bitUnpack((U8 *)&tempu8, 1); if (tempu8) { // value bitpack.bitUnpack((U8 *)&tempu8, 1); if (tempu8) { // negative patches[i] = -1; } else { // positive patches[i] = 1; } if (wbits <= 8) { bitpack.bitUnpack((U8 *)&tempu8, wbits); patches[i] *= tempu8; } else if (wbits <= 16) { tempu16 = 0; U8 *ret = (U8 *)&tempu16; bitpack.bitUnpack(&(ret[1]), 8); bitpack.bitUnpack(&(ret[0]), wbits - 8); patches[i] *= tempu16; } else if (wbits <= 24) { tempu32 = 0; U8 *ret = (U8 *)&tempu32; bitpack.bitUnpack(&(ret[2]), 8); bitpack.bitUnpack(&(ret[1]), 8); bitpack.bitUnpack(&(ret[0]), wbits - 16); patches[i] *= tempu32; } else if (wbits <= 32) { tempu32 = 0; U8 *ret = (U8 *)&tempu32; bitpack.bitUnpack(&(ret[3]), 8); bitpack.bitUnpack(&(ret[2]), 8); bitpack.bitUnpack(&(ret[1]), 8); bitpack.bitUnpack(&(ret[0]), wbits - 24); patches[i] *= tempu32; } } else { for (j = i; j < patch_size*patch_size; j++) { patches[j] = 0; } return; } } else { patches[i] = 0; } } #else S32 i, j, patch_size = gPatchSize, wbits = gWordBits; U32 temp; for (i = 0; i < patch_size*patch_size; i++) { temp = 0; bitpack.bitUnpack((U8 *)&temp, 1); if (temp) { // either 0 EOB or Value temp = 0; bitpack.bitUnpack((U8 *)&temp, 1); if (temp) { // value temp = 0; bitpack.bitUnpack((U8 *)&temp, 1); if (temp) { // negative temp = 0; bitpack.bitUnpack((U8 *)&temp, wbits); patches[i] = temp; patches[i] *= -1; } else { // positive temp = 0; bitpack.bitUnpack((U8 *)&temp, wbits); patches[i] = temp; } } else { for (j = i; j < patch_size*patch_size; j++) { patches[j] = 0; } return; } } else { patches[i] = 0; } } #endif }