// texture manager #include "pch.h" #define MAX 32 // // local and external data // static TexEntry tcache[MAX]; static unsigned tptr; static UINT texlist[MAX+1]; // gl texture list (0 entry reserved) static uint8_t tlut[1024 * 1024]; // temporary TLUT buffer TexEntry *tID[8]; // texture unit bindings Color rgbabuf[1024 * 1024]; // --------------------------------------------------------------------------- void TexInit() { memset(tcache, 0, sizeof(tcache)); tptr = 1; glGenTextures(MAX, texlist); for(unsigned n=1; nRGBA); rgb[0] = c.B; // B rgb[1] = c.G; // G rgb[2] = c.R; // R rgbaBuf++; fwrite(rgb, 1, 3, f); } } } fclose(f); } static void GetTlutCol(Color *c, unsigned id, unsigned entry) { uint16_t *tptr = (uint16_t *)(&tlut[(bpRegs.settlut[id].tmem << 9) + 2 * entry]); int fmt = bpRegs.settlut[id].fmt; switch(fmt) { case 0: // IA8 { c->A = *tptr & 0xff; c->R = c->G = c->B = *tptr >> 8; } return; case 1: // RGB565 { uint16_t p = _byteswap_ushort(*tptr); uint8_t r = p >> 11; uint8_t g = (p >> 5) & 0x3f; uint8_t b = p & 0x1f; c->R = (r << 3) | (r >> 2); c->G = (g << 2) | (g >> 4); c->B = (b << 3) | (b >> 2); c->A = 255; } return; case 2: // RGB5A3 { uint16_t p = _byteswap_ushort(*tptr); if(p >> 15) { p &= ~0x8000; // clear A-bit uint8_t r = p >> 10; uint8_t g = (p >> 5) & 0x1f; uint8_t b = p & 0x1f; c->R = (r << 3) | (r >> 2); c->G = (g << 3) | (g >> 2); c->B = (b << 3) | (b >> 2); c->A = 255; } else { uint8_t r = (p >> 8) & 0xf; uint8_t g = (p >> 4) & 0xf; uint8_t b = p & 0xf; uint8_t a = p >> 12; c->R = (r << 4) | r; c->G = (g << 4) | g; c->B = (b << 4) | b; c->A = a | (a << 3) | ((a << 9) & 3); } } return; default: { DBHalt("GX: Unknown TLUT format: %i", fmt); } } } void RebindTexture(unsigned id) { glBindTexture(GL_TEXTURE_2D, tID[id]->bind); // parameters // check for extension ? #ifndef GL_MIRRORED_REPEAT_ARB #define GL_MIRRORED_REPEAT_ARB 0x8370 #endif static uint32_t wrap[4] = { GL_CLAMP, GL_REPEAT, GL_MIRRORED_REPEAT_ARB, GL_REPEAT }; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap[bpRegs.texmode0[id].wrap_s]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap[bpRegs.texmode0[id].wrap_t]); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, TEXMODE); static uint32_t filt[] = { GL_NEAREST, GL_LINEAR, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR }; glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filt[bpRegs.texmode0[id].min]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filt[bpRegs.texmode0[id].mag]); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tID[id]->dw, tID[id]->dh, 0, GL_RGBA, GL_UNSIGNED_BYTE, tID[id]->rgbaData ); } void LoadTexture(uint32_t addr, int id, int fmt, int width, int height) { BOOL doDump = FALSE; Color *texbuf; int oldw, oldh; DWORD w, h; unsigned n; // check cache entries for coincidence /*/ for(n=1; n= 8) break; if( (tcache[n].ramAddr == addr) && (tcache[n].fmt == fmt ) && (tcache[n].w == width ) && (tcache[n].h == height ) ) { tID[id] = &tcache[n]; return; } } /*/ n = 1; // free /*/ if(tcache[n].rgbaData) { free(tcache[n].rgbaData); tcache[n].rgbaData = NULL; } /*/ // new n = tptr; tcache[n].ramAddr = addr; tcache[n].rawData = &RAM[addr & RAMMASK]; tcache[n].fmt = fmt; // aspect tcache[n].ds = tcache[n].dt = 1.0f; _BitScanReverse(&w, width); if(width & ((1 << w) - 1)) w = 1 << (w+1); else w = width; tcache[n].ds = (float)width / (float)w; _BitScanReverse(&h, height); if(height & ((1 << h) - 1)) h = 1 << (h+1); else h = height; tcache[n].dt = (float)height / (float)h; oldw = width; oldh = height; tcache[n].w = oldw; width = tcache[n].dw = w; tcache[n].h = oldh; height = tcache[n].dh = h; // allocate /*/ tcache[n].rgbaData = (Color *)malloc(width * height * 4); ASSERT(tcache[n].rgbaData == NULL); /*/ tcache[n].rgbaData = rgbabuf; texbuf = tcache[n].rgbaData; // convert texture switch(fmt) { // "intensity 4". 2 texels per byte, grayscale 0..15 case TF_I4: { int s, t, u, v; uint8_t *ptr = tcache[n].rawData; // TODO : unroll for(t=0; t> 4) | (*ptr & 0xf0); ofs++; texbuf[ofs].R = texbuf[ofs].G = texbuf[ofs].B = texbuf[ofs].A = (*ptr << 4) | (*ptr & 0x0f); ptr++; } break; } // intensity 8-bit. R=G=B=A=I8. case TF_I8: { int s, t, u, v; uint8_t *ptr = tcache[n].rawData; for(t=0; t> 4; texbuf[ofs].RGBA = _byteswap_ulong(texbuf[ofs].RGBA); ptr++; } break; } case TF_IA8: { int s, t, u, v; uint8_t *ptr = tcache[n].rawData; // TODO : unroll for(t=0; t> 11; uint8_t g = (p >> 5) & 0x3f; uint8_t b = p & 0x1f; texbuf[ofs].R = (r << 3) | (r >> 2); texbuf[ofs].G = (g << 2) | (g >> 4); texbuf[ofs].B = (b << 3) | (b >> 2); texbuf[ofs].A = 255; texbuf[ofs].RGBA = _byteswap_ulong(texbuf[ofs].RGBA); } break; } case TF_RGB5A3: { int s, t, u, v; uint16_t *ptr = (uint16_t *)tcache[n].rawData; // TODO : unroll for(t=0; t> 15) { p &= ~0x8000; // clear A-bit uint8_t r = p >> 10; uint8_t g = (p >> 5) & 0x1f; uint8_t b = p & 0x1f; texbuf[ofs].R = (r << 3) | (r >> 2); texbuf[ofs].G = (g << 3) | (g >> 2); texbuf[ofs].B = (b << 3) | (b >> 2); texbuf[ofs].A = 255; } else { uint8_t r = (p >> 8) & 0xf; uint8_t g = (p >> 4) & 0xf; uint8_t b = p & 0xf; uint8_t a = p >> 12; texbuf[ofs].R = (r << 4) | r; texbuf[ofs].G = (g << 4) | g; texbuf[ofs].B = (b << 4) | b; texbuf[ofs].A = a | (a << 3) | ((a << 9) & 3); } texbuf[ofs].RGBA = _byteswap_ulong(texbuf[ofs].RGBA); } break; } case TF_RGBA8: { int s, t, u, v; uint8_t *ptr = tcache[n].rawData; // TODO : unroll for(t=0; t> 4); texbuf[ofs].RGBA = _byteswap_ulong(rgba.RGBA); ofs++; GetTlutCol(&rgba, id, e & 0xf); texbuf[ofs].RGBA = _byteswap_ulong(rgba.RGBA); } break; } case TF_C8: { int s, t, u, v; uint8_t *ptr = tcache[n].rawData; Color rgba; // TODO : unroll for(t=0; t> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[0].R = (r << 3) | (r >> 2); rgb[0].G = (g << 2) | (g >> 4); rgb[0].B = (b << 3) | (b >> 2); p = _byteswap_ushort(blk.rgb1); r = p >> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[1].R = (r << 3) | (r >> 2); rgb[1].G = (g << 2) | (g >> 4); rgb[1].B = (b << 3) | (b >> 2); // interpolate two other if(blk.rgb0 > blk.rgb1) { rgb[2].R = (2 * rgb[0].R + rgb[1].R) / 3; rgb[2].G = (2 * rgb[0].G + rgb[1].G) / 3; rgb[2].B = (2 * rgb[0].B + rgb[1].B) / 3; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = 255; } else { rgb[2].R = (rgb[0].R + rgb[1].R) / 2; rgb[2].G = (rgb[0].G + rgb[1].G) / 2; rgb[2].B = (rgb[0].B + rgb[1].B) / 2; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = (2 * rgb[1].A + rgb[0].A) / 3; } uint8_t texel = blk.row[tnum++]; int shft; for(u=0, shft=6; u<4; u++, shft-=2) { unsigned ofs = width * (t + v) + s + u; uint8_t p = (texel >> shft) & 3; texbuf[ofs].RGBA = _byteswap_ulong(rgb[p].RGBA); } } tnum = 0; memcpy(&blk, ptr, sizeof(S3TC_BLK)); ptr += sizeof(S3TC_BLK); for(v=0; v<4; v++) { p = _byteswap_ushort(blk.rgb0); r = p >> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[0].R = (r << 3) | (r >> 2); rgb[0].G = (g << 2) | (g >> 4); rgb[0].B = (b << 3) | (b >> 2); p = _byteswap_ushort(blk.rgb1); r = p >> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[1].R = (r << 3) | (r >> 2); rgb[1].G = (g << 2) | (g >> 4); rgb[1].B = (b << 3) | (b >> 2); // interpolate two other if(blk.rgb0 > blk.rgb1) { rgb[2].R = (2 * rgb[0].R + rgb[1].R) / 3; rgb[2].G = (2 * rgb[0].G + rgb[1].G) / 3; rgb[2].B = (2 * rgb[0].B + rgb[1].B) / 3; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = 255; } else { rgb[2].R = (rgb[0].R + rgb[1].R) / 2; rgb[2].G = (rgb[0].G + rgb[1].G) / 2; rgb[2].B = (rgb[0].B + rgb[1].B) / 2; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = (2 * rgb[1].A + rgb[0].A) / 3; } uint8_t texel = blk.row[tnum++]; int shft; for(u=4, shft=6; u<8; u++, shft-=2) { unsigned ofs = width * (t + v) + s + u; uint8_t p = (texel >> shft) & 3; texbuf[ofs].RGBA = _byteswap_ulong(rgb[p].RGBA); } } tnum = 0; memcpy(&blk, ptr, sizeof(S3TC_BLK)); ptr += sizeof(S3TC_BLK); for(v=4; v<8; v++) { p = _byteswap_ushort(blk.rgb0); r = p >> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[0].R = (r << 3) | (r >> 2); rgb[0].G = (g << 2) | (g >> 4); rgb[0].B = (b << 3) | (b >> 2); p = _byteswap_ushort(blk.rgb1); r = p >> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[1].R = (r << 3) | (r >> 2); rgb[1].G = (g << 2) | (g >> 4); rgb[1].B = (b << 3) | (b >> 2); // interpolate two other if(blk.rgb0 > blk.rgb1) { rgb[2].R = (2 * rgb[0].R + rgb[1].R) / 3; rgb[2].G = (2 * rgb[0].G + rgb[1].G) / 3; rgb[2].B = (2 * rgb[0].B + rgb[1].B) / 3; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = 255; } else { rgb[2].R = (rgb[0].R + rgb[1].R) / 2; rgb[2].G = (rgb[0].G + rgb[1].G) / 2; rgb[2].B = (rgb[0].B + rgb[1].B) / 2; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = (2 * rgb[1].A + rgb[0].A) / 3; } uint8_t texel = blk.row[tnum++]; int shft; for(u=0, shft=6; u<4; u++, shft-=2) { unsigned ofs = width * (t + v) + s + u; uint8_t p = (texel >> shft) & 3; texbuf[ofs].RGBA = _byteswap_ulong(rgb[p].RGBA); } } tnum = 0; memcpy(&blk, ptr, sizeof(S3TC_BLK)); ptr += sizeof(S3TC_BLK); for(v=4; v<8; v++) { p = _byteswap_ushort(blk.rgb0); r = p >> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[0].R = (r << 3) | (r >> 2); rgb[0].G = (g << 2) | (g >> 4); rgb[0].B = (b << 3) | (b >> 2); rgb[0].A = 255; p = _byteswap_ushort(blk.rgb1); r = p >> 11; g = (p >> 5) & 0x3f; b = p & 0x1f; rgb[1].R = (r << 3) | (r >> 2); rgb[1].G = (g << 2) | (g >> 4); rgb[1].B = (b << 3) | (b >> 2); rgb[1].A = 255; // interpolate two other if(blk.rgb0 > blk.rgb1) { rgb[2].R = (2 * rgb[0].R + rgb[1].R) / 3; rgb[2].G = (2 * rgb[0].G + rgb[1].G) / 3; rgb[2].B = (2 * rgb[0].B + rgb[1].B) / 3; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = 255; } else { rgb[2].R = (rgb[0].R + rgb[1].R) / 2; rgb[2].G = (rgb[0].G + rgb[1].G) / 2; rgb[2].B = (rgb[0].B + rgb[1].B) / 2; rgb[2].A = 255; rgb[3].R = (2 * rgb[1].R + rgb[0].R) / 3; rgb[3].G = (2 * rgb[1].G + rgb[0].G) / 3; rgb[3].B = (2 * rgb[1].B + rgb[0].B) / 3; rgb[3].A = (2 * rgb[1].A + rgb[0].A) / 3; } uint8_t texel = blk.row[tnum++]; int shft; for(u=4, shft=6; u<8; u++, shft-=2) { unsigned ofs = width * (t + v) + s + u; uint8_t p = (texel >> shft) & 3; texbuf[ofs].RGBA = _byteswap_ulong(rgb[p].RGBA); } } } break; }; //default: //GFXError("Unknown texture format : %i\n", fmt); } // dump if(doDump) { DumpTexture( texbuf, addr, fmt, width, height ); } // save tID[id] = &tcache[n]; /*/ tptr++; if(tptr >= MAX) { tptr = 1; tcache[tptr].ramAddr = 0; } /*/ RebindTexture(id); } void LoadTlut(uint32_t addr, uint32_t tmem, uint32_t cnt) { assert(tmem < sizeof(tlut)); memcpy(&tlut[tmem], &RAM[addr], cnt * 16 * 2); }