/* Residual - Virtual machine to run LucasArts' 3D adventure games * * Residual is the legal property of its developers, whose names * are too numerous to list here. Please refer to the AUTHORS * file distributed with this source distribution. * * 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; either * version 2.1 of the License, or (at your option) any later version. * 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 * * $URL$ * $Id$ * */ #include "debug.h" #include "colormap.h" #include "material.h" #include "texture_manager.h" static int twiddletab[1024]; static void init_twiddletab() { int x; for(x=0; x<1024; x++) twiddletab[x] = (x&1)|((x&2)<<1)|((x&4)<<2)|((x&8)<<3)|((x&16)<<4)| ((x&32)<<5)|((x&64)<<6)|((x&128)<<7)|((x&256)<<8)|((x&512)<<9); } TextureManager::Texture::Texture(uint16 *tex, unsigned int fsz, int width, int height, int cnt) : _data(tex), _width(width), _height(height), _cnt(cnt), _framesize(fsz) { _texture = TA_TEXTUREMODE_ARGB1555|TA_TEXTUREMODE_ADDRESS(_data); _mode2 = TA_POLYMODE2_BLEND_SRC|TA_POLYMODE2_FOG_DISABLED| TA_POLYMODE2_TEXTURE_REPLACE|TA_POLYMODE2_BILINEAR_FILTER; switch(_width) { case 4: /* XXX */ case 8: _mode2 |= TA_POLYMODE2_U_SIZE_8; _uscale = 1.0/8; break; case 16: _mode2 |= TA_POLYMODE2_U_SIZE_16; _uscale = 1.0/16; break; case 32: _mode2 |= TA_POLYMODE2_U_SIZE_32; _uscale = 1.0/32; break; case 64: _mode2 |= TA_POLYMODE2_U_SIZE_64; _uscale = 1.0/64; break; case 128: _mode2 |= TA_POLYMODE2_U_SIZE_128; _uscale = 1.0/128; break; case 256: _mode2 |= TA_POLYMODE2_U_SIZE_256; _uscale = 1.0/256; break; default: assert(0); break; } switch(_height) { case 4: /* XXX */ case 8: _mode2 |= TA_POLYMODE2_V_SIZE_8; _vscale = 1.0/8; break; case 16: _mode2 |= TA_POLYMODE2_V_SIZE_16; _vscale = 1.0/16; break; case 32: _mode2 |= TA_POLYMODE2_V_SIZE_32; _vscale = 1.0/32; break; case 64: _mode2 |= TA_POLYMODE2_V_SIZE_64; _vscale = 1.0/64; break; case 128: _mode2 |= TA_POLYMODE2_V_SIZE_128; _vscale = 1.0/128; break; case 256: _mode2 |= TA_POLYMODE2_V_SIZE_256; _vscale = 1.0/256; break; default: assert(0); break; } assert((_width > 4 && _height > 4) || (_width == 4 && _height == 4)); } void TextureManager::Texture:: setTextureTwiddled(uint16 *tex, const uint8 *data, const CMap *cmap, int sz, int extra) { for(int y=0; y_colors+3*n; t = 0x8000 | ((c[0]<<7)&0x7c00)| ((c[1]<<2)&0x03e0)| ((c[2]>>3)&0x001f); } *(uint16*)(((twiddletab[x]<<2)|(twiddletab[y]<<1)) + (char *)tex) = t; } } void TextureManager::Texture::setTexture(int n, const uint8 *data, const CMap *cmap) { uint16 *tex = (uint16 *)(n * _framesize + (char *)_data); if(_width == _height) setTextureTwiddled(tex, data, cmap, _width); else if(_width > _height) { const uint8 *d2 = data; uint16 *t2 = tex; unsigned int fsz = _height * _height * 2; for(int x = 0; x < _width; x += _height) { setTextureTwiddled(t2, d2, cmap, _height, _width - _height); d2 += _height; t2 += _height * _height; } } else { const uint8 *d2 = data; uint16 *t2 = tex; for(int x = 0; x < _height; x += _width) { setTextureTwiddled(t2, d2, cmap, _width); d2 += _width * _width; t2 += _width * _width; } } } TextureManager::Texture *TextureManager::allocateTexture(int width, int height, int cnt) { unsigned int framesize = width * height * 2; uint16 *tex = (uint16 *) allocateTexMem(framesize * cnt); return new Texture(tex, framesize, width, height, cnt); } void TextureManager::freeTexture(Texture *t) { freeTexMem(t->getMemory(), t->getFrameSize()*t->getCnt()); delete t; } void *TextureManager::allocateTexMem(unsigned int size) { assert(size > 0 && !(size&7)); // First fit FreeListNode *n, **link; for(link = &_freeListHead; (n = *link) != NULL; link = &n->next) if(n->size >= size) break; assert(n != NULL); if(n->size > size) { FreeListNode *n2 = (FreeListNode *)(size + (char *)n); n2->size = n->size - size; n2->next = n->next; *link = n2; } else { *link = n->next; } return (void *)n; } void TextureManager::freeTexMem(void *mem, unsigned int size) { assert(size > 0 && !(size&7) && mem != NULL); FreeListNode *n, **link; for(link = &_freeListHead; (n = *link) != NULL; link = &n->next) if(mem == (n->size + (char *)n)) break; else if(mem < n) { n = NULL; break; } else assert(mem > (n->size + (char *)n)); if(n == NULL) { n = (FreeListNode *)mem; n->size = size; n->next = *link; *link = n; } else { n->size += size; } // Join this block with the next one if possible if((char *)n->next == n->size + (char *)n) { n->size += n->next->size; n->next = n->next->next; } assert(n->next == NULL || (char *)n->next > n->size + (char *)n); } void TextureManager::initTextures() { unsigned int aperture = 0x180000; _freeListHead = (FreeListNode *)ta_txalloc(aperture); _freeListHead->next = NULL; _freeListHead->size = aperture; init_twiddletab(); }