From 4883b03f2b8f060c04f054573e8f345878e93a11 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 22 Jul 2020 13:56:03 +0200 Subject: [PATCH] image masks and raster fixes --- src/d3d/d3d.cpp | 2 +- src/gl/gl3raster.cpp | 18 +- src/gl/gl3shader.cpp | 2 +- src/image.cpp | 458 +++++++++++++++++++++++++++++++++++++- src/ps2/ps2raster.cpp | 66 +++--- src/ps2/rwps2.h | 5 +- src/raster.cpp | 20 +- src/rwobjects.h | 51 ++++- src/texture.cpp | 3 +- tools/playground/main.cpp | 15 +- 10 files changed, 569 insertions(+), 71 deletions(-) diff --git a/src/d3d/d3d.cpp b/src/d3d/d3d.cpp index bdc3629..2278723 100644 --- a/src/d3d/d3d.cpp +++ b/src/d3d/d3d.cpp @@ -741,7 +741,7 @@ rasterFromImage(Raster *raster, Image *image) truecolimg->pixels = image->pixels; truecolimg->stride = image->stride; truecolimg->palette = image->palette; - truecolimg->unindex(); + truecolimg->unpalettize(); image = truecolimg; } diff --git a/src/gl/gl3raster.cpp b/src/gl/gl3raster.cpp index 1d1b62e..85d12e5 100644 --- a/src/gl/gl3raster.cpp +++ b/src/gl/gl3raster.cpp @@ -371,7 +371,7 @@ rasterFromImage(Raster *raster, Image *image) truecolimg->pixels = image->pixels; truecolimg->stride = image->stride; truecolimg->palette = image->palette; - truecolimg->unindex(); + truecolimg->unpalettize(); image = truecolimg; } @@ -379,34 +379,34 @@ rasterFromImage(Raster *raster, Image *image) switch(image->depth){ case 32: #ifdef RW_GLES - conv = conv_RGBA8888_to_RGBA8888; + conv = conv_RGBA8888_from_RGBA8888; #else if(raster->format == Raster::C8888) - conv = conv_RGBA8888_to_RGBA8888; + conv = conv_RGBA8888_from_RGBA8888; else if(raster->format == Raster::C888) - conv = conv_RGB888_to_RGB888; + conv = conv_RGB888_from_RGB888; else goto err; #endif break; case 24: #ifdef RW_GLES - conv = conv_RGB888_to_RGBA8888; + conv = conv_RGB888_from_RGBA8888; #else if(raster->format == Raster::C8888) - conv = conv_RGB888_to_RGBA8888; + conv = conv_RGBA8888_from_RGB888; else if(raster->format == Raster::C888) - conv = conv_RGB888_to_RGB888; + conv = conv_RGB888_from_RGB888; else goto err; #endif break; case 16: #ifdef RW_GLES - conv = conv_RGBA1555_to_RGBA8888; + conv = conv_RGBA8888_from_ARGB1555; #else if(raster->format == Raster::C1555) - conv = conv_RGBA1555_to_RGBA5551; + conv = conv_RGBA5551_from_ARGB1555; else goto err; #endif diff --git a/src/gl/gl3shader.cpp b/src/gl/gl3shader.cpp index b3751d3..ef2af25 100644 --- a/src/gl/gl3shader.cpp +++ b/src/gl/gl3shader.cpp @@ -80,7 +80,7 @@ Shader *currentShader; static void printShaderSource(const char **src) { - int f, l; + int f; const char *file; bool printline; int line = 1; diff --git a/src/image.cpp b/src/image.cpp index 9ac8159..9e695d0 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -85,7 +85,7 @@ Image::allocate(void) } if(this->palette == nil){ if(this->depth == 4 || this->depth == 8) - this->palette = rwNewT(uint8, (this->depth==4? 16 : 256)*4, MEMDUR_EVENT | ID_IMAGE); + this->palette = rwNewT(uint8, (1 << this->depth)*4, MEMDUR_EVENT | ID_IMAGE); this->flags |= 2; } } @@ -101,6 +101,7 @@ Image::free(void) rwFree(this->palette); this->palette = nil; } + this->flags = 0; } void @@ -350,8 +351,6 @@ Image::hasAlpha(void) { uint8 ret = 0xFF; uint8 *pixels = this->pixels; - if(this->depth == 24) - return 0; if(this->depth == 32){ for(int y = 0; y < this->height; y++){ uint8 *line = pixels; @@ -361,6 +360,18 @@ Image::hasAlpha(void) } pixels += this->stride; } + }else if(this->depth == 24){ + return 0; + }else if(this->depth == 16){ + for(int y = 0; y < this->height; y++){ + uint8 *line = pixels; + for(int x = 0; x < this->width; x++){ + ret &= line[1] & 0x80; + line += 2; + } + pixels += this->stride; + } + return ret != 0x80; }else if(this->depth <= 8){ for(int y = 0; y < this->height; y++){ uint8 *line = pixels; @@ -375,14 +386,92 @@ Image::hasAlpha(void) } void -Image::unindex(void) +Image::convertTo32(void) +{ + assert(this->pixels); + uint8 *pixels = this->pixels; + int32 newstride = this->width*4; + uint8 *newpixels; + + void (*fun)(uint8 *out, uint8 *in) = nil; + switch(this->depth){ + case 4: + case 8: + assert(this->palette); + this->unpalettize(true); + return; + case 16: + fun = conv_RGBA8888_from_ARGB1555; + break; + case 24: + fun = conv_RGBA8888_from_RGB888; + break; + default: + return; + } + + newpixels = rwNewT(uint8, newstride*this->height, MEMDUR_EVENT | ID_IMAGE); + for(int y = 0; y < this->height; y++){ + uint8 *line = pixels; + uint8 *newline = newpixels; + for(int x = 0; x < this->width; x++){ + fun(newline, line); + line += this->bpp; + newline += 4; + } + pixels += this->stride; + newpixels += newstride; + } + + this->free(); + this->depth = 32; + this->bpp = 4; + this->stride = newstride; + this->pixels = nil; + this->palette = nil; + this->setPixels(newpixels); +} + +void +Image::palettize(int32 depth) +{ + RGBA colors[256]; + ColorQuant quant; + uint8 *newpixels; + uint32 newstride; + + quant.init(); + quant.addImage(this); + assert(depth <= 8); + quant.makePalette(1<width; + newpixels = rwNewT(uint8, newstride*this->height, MEMDUR_EVENT | ID_IMAGE); + // TODO: maybe do floyd-steinberg dithering? + quant.matchImage(newpixels, newstride, this); + + this->free(); + this->depth = depth; + this->bpp = depth < 8 ? 1 : depth/8; + this->stride = newstride; + this->pixels = nil; + this->palette = nil; + this->setPixels(newpixels); + this->allocate(); + memcpy(this->palette, colors, 4*(1<depth > 8) return; assert(this->pixels); assert(this->palette); - int32 ndepth = this->hasAlpha() ? 32 : 24; + int32 ndepth = (forceAlpha || this->hasAlpha()) ? 32 : 24; int32 nstride = this->width*ndepth/8; uint8 *npixels = rwNewT(uint8, nstride*this->height, MEMDUR_EVENT | ID_IMAGE); @@ -411,14 +500,89 @@ Image::unindex(void) this->setPixels(npixels); } +// Copy the biggest channel value to alpha +void +Image::makeMask(void) +{ + int32 maxcol; + switch(this->depth){ + case 4: + case 8: { + assert(this->palette); + int32 pallen = 1 << this->depth; + for(int32 i = 0; i < pallen; i++){ + maxcol = this->palette[i*4+0]; + if(this->palette[i*4+1] > maxcol) maxcol = this->palette[i*4+1]; + if(this->palette[i*4+2] > maxcol) maxcol = this->palette[i*4+2]; + this->palette[i*4+3] = maxcol; + } + break; + } + + case 16: + case 24: + this->convertTo32(); + // fallthrough + + case 32: { + assert(this->pixels); + uint8 *line = this->pixels; + uint8 *p; + for(int32 y = 0; y < this->height; y++){ + p = line; + for(int32 x = 0; x < this->width; x++){ + maxcol = p[0]; + if(p[1] > maxcol) maxcol = p[1]; + if(p[2] > maxcol) maxcol = p[2]; + p[3] = maxcol; + p += this->bpp; + } + line += this->stride; + } + break; + } + } +} + +void +Image::applyMask(Image *mask) +{ + if(this->width != mask->width || this->height != mask->height) + return; // TODO: set an error + // we could use alpha with 16 bits but what's the point? + if(mask->depth == 16 || mask->depth == 24) + return; + + this->convertTo32(); + assert(this->depth == 32); + + uint8 *line = this->pixels; + uint8 *mline = mask->pixels; + uint8 *p, *m; + for(int32 y = 0; y < this->height; y++){ + p = line; + m = mline; + for(int32 x = 0; x < this->width; x++){ + if(mask->depth == 32) + p[3] = m[3]; + else if(mask->depth <= 8) + p[3] = mask->palette[m[0]*4+3]; + p += this->bpp; + m += mask->bpp; + } + line += this->stride; + mline += mask->stride; + } +} + void Image::removeMask(void) { if(this->depth <= 8){ assert(this->palette); - int32 pallen = 4*(this->depth == 4 ? 16 : 256); + int32 pallen = 4*(1 << this->depth); for(int32 i = 0; i < pallen; i += 4) - this->palette[i] = 0xFF; + this->palette[i+3] = 0xFF; return; } if(this->depth == 24) @@ -576,6 +740,28 @@ Image::getFilename(const char *name) return nil; } +Image* +Image::readMasked(const char *imageName, const char *maskName) +{ + Image *img, *mask; + + img = read(imageName); + if(img == nil) + return nil; + if(maskName && maskName[0]){ + mask = read(maskName); + if(mask == nil) + return img; + mask->makeMask(); + int32 origDepth = img->depth; + img->applyMask(mask); + mask->destroy(); + if(origDepth <= 8 && img->depth != origDepth) + img->palettize(origDepth); + } + return img; +} + Image* Image::read(const char *imageName) { @@ -583,7 +769,7 @@ Image::read(const char *imageName) char *filename, *ext, *found; Image *img; - filename = rwNewT(char, strlen(imageName) + 20, MEMDUR_FUNCTION | ID_TEXTURE); + filename = rwNewT(char, strlen(imageName) + 20, MEMDUR_FUNCTION | ID_IMAGE); strcpy(filename, imageName); ext = filename + strlen(filename); *ext++ = '.'; @@ -652,4 +838,260 @@ Image::registerModule(void) Engine::registerPlugin(sizeof(ImageGlobals), ID_IMAGEMODULE, imageOpen, imageClose); } + + +/* + * Color Quantization + */ + +// An address for a single level is 4 bits. +// Since we have 8 bpp that is 32 bits to address any tree node. +// The lower bits address the higher level tree nodes. +// This is essentially a bit reverse and swizzle. +static uint32 +makeTreeAddr(RGBA color) +{ + int32 i; + uint32 addr = 0; + uint32 r = 1; + uint32 g = 2; + uint32 b = 4; + uint32 a = 8; + for(i = 0; i < 8; i++){ + uint32 mask = 0x80>>i; + if(color.red & mask) addr |= r; + if(color.green & mask) addr |= g; + if(color.blue & mask) addr |= b; + if(color.alpha & mask) addr |= a; + r <<= 4; + g <<= 4; + b <<= 4; + a <<= 4; + } + return addr; +} + +void +ColorQuant::Node::destroy(void) +{ + int i; + for(i = 0; i < 16; i++) + if(this->children[i]) + this->children[i]->destroy(); + if(this->link.next) + this->link.remove(); + rwFree(this); +} + +ColorQuant::Node* +ColorQuant::createNode(int32 level) +{ + int i; + ColorQuant::Node *node = rwNewT(ColorQuant::Node, 1, MEMDUR_EVENT | ID_IMAGE); + node->parent = nil; + for(i = 0; i < 16; i++) + node->children[i] = nil; + node->r = 0; + node->g = 0; + node->b = 0; + node->a = 0; + node->numPixels = 0; + node->link.init(); + + if(level == 0) + this->leaves.append(&node->link); + + return node; +} + +ColorQuant::Node* +ColorQuant::getNode(ColorQuant::Node *root, uint32 addr, int32 level) +{ + if(level == 0) + return root; + + uint32 a = addr & 0xF; + if(root->children[a] == nil){ + root->children[a] = this->createNode(level-1); + root->children[a]->parent = root; + } + + return this->getNode(root->children[a], addr>>4, level-1); +} + +ColorQuant::Node* +ColorQuant::findNode(ColorQuant::Node *root, uint32 addr, int32 level) +{ + if(level == 0) + return root; + + uint32 a = addr & 0xF; + if(root->children[a] == nil) + return root; + + return this->findNode(root->children[a], addr>>4, level-1); +} + +void +ColorQuant::reduceNode(Node *node) +{ + int i; + assert(node->numPixels == 0); + for(i = 0; i < 16; i++) + if(node->children[i]){ + node->r += node->children[i]->r; + node->g += node->children[i]->g; + node->b += node->children[i]->b; + node->a += node->children[i]->a; + node->numPixels += node->children[i]->numPixels; + node->children[i]->destroy(); + node->children[i] = nil; + } + assert(node->link.next == nil); + assert(node->link.prev == nil); + this->leaves.append(&node->link); +} + +void +ColorQuant::Node::addColor(RGBA color) +{ + this->r += color.red; + this->g += color.green; + this->b += color.blue; + this->a += color.alpha; + this->numPixels++; +} + +void +ColorQuant::init(void) +{ + this->leaves.init(); + this->root = this->createNode(QUANTDEPTH); +} + +void +ColorQuant::destroy(void) +{ + this->root->destroy(); +} + +void +ColorQuant::addColor(RGBA color) +{ + uint32 addr = makeTreeAddr(color); + ColorQuant::Node *node = this->getNode(root, addr, QUANTDEPTH); + node->addColor(color); +} + +uint8 +ColorQuant::findColor(RGBA color) +{ + uint32 addr = makeTreeAddr(color); + ColorQuant::Node *node = this->findNode(root, addr, QUANTDEPTH); + return node->numPixels; +} + +void +ColorQuant::addImage(Image *img) +{ + RGBA col; + uint8 rgba[4]; + uint8 *pixels = img->pixels; + for(int y = 0; y < img->height; y++){ + uint8 *line = pixels; + for(int x = 0; x < img->width; x++){ + uint8 *p = line; + switch(img->depth){ + case 4: case 8: + conv_RGBA8888_from_RGBA8888(rgba, &img->palette[p[0]*4]); + break; + case 32: + conv_RGBA8888_from_RGBA8888(rgba, p); + break; + case 24: + conv_RGBA8888_from_RGB888(rgba, p); + break; + case 16: + conv_RGBA8888_from_ARGB1555(rgba, p); + break; + default: assert(0 && "invalid depth"); + } + col.red = rgba[0]; + col.green = rgba[1]; + col.blue = rgba[2]; + col.alpha = rgba[3]; + this->addColor(col); + line += img->bpp; + } + pixels += img->stride; + } +} + +void +ColorQuant::makePalette(int32 numColors, RGBA *colors) +{ + while(this->leaves.count() > numColors){ + Node *n = LLLinkGetData(this->leaves.link.next, Node, link); + this->reduceNode(n->parent); + } + + int i = 0; + FORLIST(lnk, this->leaves){ + Node *n = LLLinkGetData(lnk, Node, link); + n->r /= n->numPixels; + n->g /= n->numPixels; + n->b /= n->numPixels; + n->a /= n->numPixels; + colors[i].red = n->r; + colors[i].green = n->g; + colors[i].blue = n->b; + colors[i].alpha = n->a; + n->numPixels = i++; + } +} + +void +ColorQuant::matchImage(uint8 *dstPixels, uint32 dstStride, Image *img) +{ + RGBA col; + uint8 rgba[4]; + uint8 *pixels = img->pixels; + for(int y = 0; y < img->height; y++){ + uint8 *line = pixels; + uint8 *dline = dstPixels; + for(int x = 0; x < img->width; x++){ + uint8 *p = line; + uint8 *d = dline; + switch(img->depth){ + case 4: case 8: + conv_RGBA8888_from_RGBA8888(rgba, &img->palette[p[0]*4]); + break; + case 32: + conv_RGBA8888_from_RGBA8888(rgba, p); + break; + case 24: + conv_RGBA8888_from_RGB888(rgba, p); + break; + case 16: + conv_RGBA8888_from_ARGB1555(rgba, p); + break; + default: assert(0 && "invalid depth"); + } + + col.red = rgba[0]; + col.green = rgba[1]; + col.blue = rgba[2]; + col.alpha = rgba[3]; + *d = this->findColor(col); + + line += img->bpp; + dline++; + } + pixels += img->stride; + dstPixels += dstStride; + } +} + + + } diff --git a/src/ps2/ps2raster.cpp b/src/ps2/ps2raster.cpp index 9c27cdb..b687966 100644 --- a/src/ps2/ps2raster.cpp +++ b/src/ps2/ps2raster.cpp @@ -1566,31 +1566,31 @@ rasterUnlockPalette(Raster *raster) } void -expandPSMT4(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw) +expandPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) { int32 x, y; for(y = 0; y < h; y++) for(x = 0; x < w/2; x++){ - dst[y*w + x*2 + 0] = src[y*srcw/2 + x] & 0xF; - dst[y*w + x*2 + 1] = src[y*srcw/2 + x] >> 4; + dst[y*dststride + x*2 + 0] = src[y*srcstride + x] & 0xF; + dst[y*dststride + x*2 + 1] = src[y*srcstride + x] >> 4; } } void -compressPSMT4(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw) +compressPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) { int32 x, y; for(y = 0; y < h; y++) for(x = 0; x < w/2; x++) - dst[y*srcw/2 + x] = src[y*w + x*2 + 0] | src[y*w + x*2 + 1] << 4; + dst[y*dststride + x] = src[y*srcstride + x*2 + 0] | src[y*srcstride + x*2 + 1] << 4; } void -copyPSMT8(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw) +copyPSMT8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h) { int32 x, y; for(y = 0; y < h; y++) for(x = 0; x < w; x++) - dst[y*w + x] = src[y*srcw + x]; + dst[y*dststride + x] = src[y*srcstride + x]; } // Almost the same as d3d9 and gl3 function @@ -1691,23 +1691,22 @@ rasterFromImage(Raster *raster, Image *image) int tw; transferMinSize(image->depth == 4 ? PSMT4 : PSMT8, natras->flags, &minw, &minh); tw = max(image->width, minw); - in = image->pixels; + uint8 *src = image->pixels; out = raster->lock(0, Raster::LOCKWRITE|Raster::LOCKNOFETCH); if(image->depth == 4){ - compressPSMT4(out, in, image->width, image->height, tw); + compressPSMT4(out, tw/2, src, image->stride, image->width, image->height); }else if(image->depth == 8){ - copyPSMT8(out, in, image->width, image->height, tw); + copyPSMT8(out, tw, src, image->stride, image->width, image->height); }else{ - // TODO: stride - for(int32 y = 0; y < image->height; y++) - for(int32 x = 0; x < image->width; x++) + for(int32 y = 0; y < image->height; y++){ + in = src; + for(int32 x = 0; x < image->width; x++){ switch(raster->format & 0xF00){ case Raster::C8888: out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; out[3] = in[3]*128/255; - in += 4; out += 4; break; case Raster::C888: @@ -1715,19 +1714,20 @@ rasterFromImage(Raster *raster, Image *image) out[1] = in[1]; out[2] = in[2]; out[3] = 0x80; - in += 3; out += 4; break; case Raster::C1555: - out[0] = in[0]; - out[1] = in[1]; - in += 2; + conv_ARGB1555_from_ABGR1555(out, in); out += 2; break; default: assert(0 && "unknown ps2 raster format"); break; } + in += image->bpp; + } + src += image->stride; + } } raster->unlock(0); return 1; @@ -1792,16 +1792,16 @@ rasterToImage(Raster *raster) int tw; transferMinSize(depth == 4 ? PSMT4 : PSMT8, natras->flags, &minw, &minh); tw = max(raster->width, minw); - out = image->pixels; + uint8 *dst = image->pixels; in = raster->lock(0, Raster::LOCKREAD); if(depth == 4){ - expandPSMT4(out, in, raster->width, raster->height, tw); + expandPSMT4(dst, image->stride, in, tw/2, raster->width, raster->height); }else if(depth == 8){ - copyPSMT8(out, in, raster->width, raster->height, tw); - }else - // TODO: stride - for(int32 y = 0; y < image->height; y++) - for(int32 x = 0; x < image->width; x++) + copyPSMT8(dst, image->stride, in, tw, raster->width, raster->height); + }else{ + for(int32 y = 0; y < image->height; y++){ + out = dst; + for(int32 x = 0; x < image->width; x++){ switch(raster->format & 0xF00){ case Raster::C8888: out[0] = in[0]; @@ -1809,31 +1809,31 @@ rasterToImage(Raster *raster) out[2] = in[2]; out[3] = in[3]*255/128; in += 4; - out += 4; break; case Raster::C888: out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; in += 4; - out += 3; break; case Raster::C1555: - out[0] = in[0]; - out[1] = in[1]; + conv_ARGB1555_from_ABGR1555(out, in); in += 2; - out += 2; break; case Raster::C555: - out[0] = in[0]; - out[1] = in[1] | 0x80; + conv_ARGB1555_from_ABGR1555(out, in); + out[1] |= 0x80; in += 2; - out += 2; break; default: assert(0 && "unknown ps2 raster format"); break; } + out += image->bpp; + } + dst += image->stride; + } + } raster->unlock(0); return image; diff --git a/src/ps2/rwps2.h b/src/ps2/rwps2.h index fbf66ec..baf8bc8 100644 --- a/src/ps2/rwps2.h +++ b/src/ps2/rwps2.h @@ -223,8 +223,9 @@ Texture *readNativeTexture(Stream *stream); void writeNativeTexture(Texture *tex, Stream *stream); uint32 getSizeNativeTexture(Texture *tex); -void expandPSMT4(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw); -void copyPSMT8(uint8 *dst, uint8 *src, int32 w, int32 h, int32 srcw); +void expandPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h); +void compressPSMT4(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h); +void copyPSMT8(uint8 *dst, uint32 dststride, uint8 *src, uint32 srcstride, int32 w, int32 h); } } diff --git a/src/raster.cpp b/src/raster.cpp index 866014f..6422081 100644 --- a/src/raster.cpp +++ b/src/raster.cpp @@ -222,7 +222,7 @@ Raster::renderFast(int32 x, int32 y) } void -conv_RGBA8888_to_RGBA8888(uint8 *out, uint8 *in) +conv_RGBA8888_from_RGBA8888(uint8 *out, uint8 *in) { out[0] = in[0]; out[1] = in[1]; @@ -231,7 +231,7 @@ conv_RGBA8888_to_RGBA8888(uint8 *out, uint8 *in) } void -conv_RGB888_to_RGBA8888(uint8 *out, uint8 *in) +conv_RGBA8888_from_RGB888(uint8 *out, uint8 *in) { out[0] = in[0]; out[1] = in[1]; @@ -240,7 +240,7 @@ conv_RGB888_to_RGBA8888(uint8 *out, uint8 *in) } void -conv_RGB888_to_RGB888(uint8 *out, uint8 *in) +conv_RGB888_from_RGB888(uint8 *out, uint8 *in) { out[0] = in[0]; out[1] = in[1]; @@ -248,7 +248,7 @@ conv_RGB888_to_RGB888(uint8 *out, uint8 *in) } void -conv_RGBA1555_to_RGBA5551(uint8 *out, uint8 *in) +conv_RGBA5551_from_ARGB1555(uint8 *out, uint8 *in) { uint32 r, g, b, a; a = (in[1]>>7) & 1; @@ -260,7 +260,7 @@ conv_RGBA1555_to_RGBA5551(uint8 *out, uint8 *in) } void -conv_RGBA1555_to_RGBA8888(uint8 *out, uint8 *in) +conv_RGBA8888_from_ARGB1555(uint8 *out, uint8 *in) { uint32 r, g, b, a; a = (in[1]>>7) & 1; @@ -273,4 +273,14 @@ conv_RGBA1555_to_RGBA8888(uint8 *out, uint8 *in) out[3] = a*0xFF; } +void +conv_ABGR1555_from_ARGB1555(uint8 *out, uint8 *in) +{ + uint32 r, b; + r = (in[1]>>2) & 0x1F; + b = in[0] & 0x1F; + out[1] = in[1]&0x83 | b<<2; + out[0] = in[0]&0xE0 | r; +} + } diff --git a/src/rwobjects.h b/src/rwobjects.h index 1ffcd1f..b281404 100644 --- a/src/rwobjects.h +++ b/src/rwobjects.h @@ -142,7 +142,11 @@ struct Image void setPixelsDXT(int32 type, uint8 *pixels); void setPalette(uint8 *palette); bool32 hasAlpha(void); - void unindex(void); + void convertTo32(void); + void palettize(int32 depth); + void unpalettize(bool forceAlpha = false); + void makeMask(void); + void applyMask(Image *mask); void removeMask(void); Image *extractMask(void); @@ -150,6 +154,7 @@ struct Image static void printSearchPath(void); static char *getFilename(const char*); static Image *read(const char *imageName); + static Image *readMasked(const char *imageName, const char *maskName); typedef Image *(*fileRead)(const char *afilename); @@ -166,6 +171,38 @@ void writeTGA(Image *image, const char *filename); Image *readBMP(const char *filename); void writeBMP(Image *image, const char *filename); +enum { QUANTDEPTH = 8 }; + +struct ColorQuant +{ + struct Node { + uint32 r, g, b, a; + int32 numPixels; + Node *parent; + Node *children[16]; + LLLink link; + + void destroy(void); + void addColor(RGBA color); + bool isLeaf(void) { for(int32 i = 0; i < 16; i++) if(this->children[i]) return false; return true; } + }; + + Node *root; + LinkList leaves; + + void init(void); + void destroy(void); + Node *createNode(int32 level); + Node *getNode(Node *root, uint32 addr, int32 level); + Node *findNode(Node *root, uint32 addr, int32 level); + void reduceNode(Node *node); + void addColor(RGBA color); + uint8 findColor(RGBA color); + void addImage(Image *img); + void makePalette(int32 numColors, RGBA *colors); + void matchImage(uint8 *dstPixels, uint32 dstStride, Image *src); +}; + // used to emulate d3d and xbox textures struct RasterLevels { @@ -265,11 +302,13 @@ struct Raster }; }; -void conv_RGBA8888_to_RGBA8888(uint8 *out, uint8 *in); -void conv_RGB888_to_RGBA8888(uint8 *out, uint8 *in); -void conv_RGB888_to_RGB888(uint8 *out, uint8 *in); -void conv_RGBA1555_to_RGBA5551(uint8 *out, uint8 *in); -void conv_RGBA1555_to_RGBA8888(uint8 *out, uint8 *in); +void conv_RGBA8888_from_RGBA8888(uint8 *out, uint8 *in); +void conv_RGBA8888_from_RGB888(uint8 *out, uint8 *in); +void conv_RGB888_from_RGB888(uint8 *out, uint8 *in); +void conv_RGBA5551_from_ARGB1555(uint8 *out, uint8 *in); +void conv_RGBA8888_from_ARGB1555(uint8 *out, uint8 *in); +void conv_ABGR1555_from_ARGB1555(uint8 *out, uint8 *in); +inline void conv_ARGB1555_from_ABGR1555(uint8 *out, uint8 *in) { conv_ABGR1555_from_ARGB1555(out, in); } #define IGNORERASTERIMP 0 diff --git a/src/texture.cpp b/src/texture.cpp index 652ee6a..f40b086 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -299,14 +299,13 @@ defaultFindCB(const char *name) } -// TODO: actually read the mask! static Texture* defaultReadCB(const char *name, const char *mask) { Texture *tex; Image *img; - img = Image::read(name); + img = Image::readMasked(name, mask); if(img){ tex = Texture::create(Raster::createFromImage(img)); strncpy(tex->name, name, 32); diff --git a/tools/playground/main.cpp b/tools/playground/main.cpp index b0d8ebd..2993161 100644 --- a/tools/playground/main.cpp +++ b/tools/playground/main.cpp @@ -27,6 +27,9 @@ void genIm3DEnd(void); void initFont(void); void printScreen(const char *s, float x, float y); +void initsplines(void); +void rendersplines(void); + rw::Charset *testfont; //#include @@ -236,7 +239,7 @@ InitRW(void) Scene.camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1); camera->m_rwcam = Scene.camera; camera->m_aspectRatio = 640.0f/448.0f; - camera->m_near = 5.0f; + camera->m_near = 0.5f; // camera->m_far = 450.0f; camera->m_far = 15.0f; camera->m_target.set(0.0f, 0.0f, 0.0f); @@ -248,6 +251,8 @@ InitRW(void) Scene.world->addCamera(camera->m_rwcam); + initsplines(); + return true; } @@ -382,7 +387,7 @@ Draw(float timeDelta) { getFrontBuffer(); - static rw::RGBA clearcol = { 0x60, 0x60, 0x60, 0xFF }; + static rw::RGBA clearcol = { 161, 161, 161, 0xFF }; camera->m_rwcam->clear(&clearcol, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ); camera->update(); camera->m_rwcam->beginUpdate(); @@ -401,10 +406,12 @@ extern void endSoftras(void); // im2dtest(); // Scene.clump->render(); - im3dtest(); +// im3dtest(); // printScreen("Hello, World!", 10, 10); - testfont->print("foo ABC", 200, 200, true); +// testfont->print("foo ABC", 200, 200, true); + + rendersplines(); camera->m_rwcam->endUpdate();