diff --git a/Minecraft.Client/Texture.cpp b/Minecraft.Client/Texture.cpp index f607ee69..1b8bab89 100644 --- a/Minecraft.Client/Texture.cpp +++ b/Minecraft.Client/Texture.cpp @@ -14,10 +14,6 @@ Texture::Texture(const wstring &name, int mode, int width, int height, int depth void Texture::_init(const wstring &name, int mode, int width, int height, int depth, int wrapMode, int format, int minFilter, int magFilter, bool mipMap) { -#ifdef __PS3__ - if(g_texBlitJobQueuePort == nullptr) - g_texBlitJobQueuePort = new C4JSpursJobQueue::Port("C4JSpursJob_Texture_blit"); -#endif this->name = name; this->mode = mode; this->width = width; @@ -29,25 +25,9 @@ void Texture::_init(const wstring &name, int mode, int width, int height, int de this->wrapMode = wrapMode; immediateUpdate = false; m_bInitialised = false; - for( int i = 0 ; i < 10; i++ ) - { - data[i] = nullptr; - } rect = new Rect2i(0, 0, width, height); - // 4J Removed 1D and 3D - //if (height == 1 && depth == 1) - //{ - // type = GL_TEXTURE_1D; - //} - //else if(depth == 1) - //{ - type = GL_TEXTURE_2D; - //} - //else - //{ - // type = GL_TEXTURE_3D; - //} + type = GL_TEXTURE_2D; mipmapped = mipMap || (minFilter != GL_NEAREST && minFilter != GL_LINEAR) || (magFilter != GL_NEAREST && magFilter != GL_LINEAR); @@ -67,13 +47,8 @@ void Texture::_init(const wstring &name, int mode, int width, int height, int de if(m_iMipLevels > MAX_MIP_LEVELS) m_iMipLevels = MAX_MIP_LEVELS; } -#ifdef __PSVITA__ - // vita doesn't have a mipmap conditional shader because it's too slow so make sure this texture don't look awful at the lower mips - if( name == L"terrain" ) - { - m_iMipLevels = 3; - } -#endif + for( int i = 0 ; i < m_iMipLevels; i++ ) + data[i] = nullptr; if (mode != TM_CONTAINER) { @@ -86,9 +61,7 @@ void Texture::_init(const wstring &name, int mode, int width, int height, int de glTexParameteri(type, GL_TEXTURE_WRAP_T, wrapMode); } else - { glId = -1; - } managerId = TextureManager::getInstance()->createTextureID(); } @@ -98,63 +71,41 @@ void Texture::_init(const wstring &name, int mode, int width, int height, int de _init(name, mode, width, height, depth, wrapMode, format, minFilter, magFilter, mipMap); if (image == nullptr) { - if (width == -1 || height == -1) + if (width <= 0 || height <= 0) { valid = false; + return; } - else + + int baseSize = width * height * depth * 4; + + data[0] = ByteBuffer::allocateDirect(baseSize); + + memset(data[0]->getBuffer(), 0, baseSize); + + data[0]->position(0)->limit(baseSize); + + if(mipmapped) { - byteArray tempBytes = byteArray(width * height * depth * 4); - for (int index = 0; index < tempBytes.length; index++) + for(unsigned int level = 1; level < m_iMipLevels; ++level) { - tempBytes[index] = 0; - } -#ifdef __PS3__ - data[0] = new ByteBuffer_IO(tempBytes.length); -#else - data[0] = ByteBuffer::allocateDirect(tempBytes.length); -#endif // __{S3__ - data[0]->clear(); - data[0]->put(tempBytes); - data[0]->position(0)->limit(tempBytes.length); + int ww = std::max(1, width >> level); + int hh = std::max(1, height >> level); - delete [] tempBytes.data; + int mipSize = ww * hh * depth * 4; - if(mipmapped) - { - for(unsigned int level = 1; level < m_iMipLevels; ++level) - { - int ww = width >> level; - int hh = height >> height; + data[level] = ByteBuffer::allocateDirect(mipSize); - byteArray tempBytes = byteArray(ww * hh * depth * 4); - for (int index = 0; index < tempBytes.length; index++) - { - tempBytes[index] = 0; - } + memset(data[level]->getBuffer(), 0, mipSize); -#ifdef __PS3__ - data[level] = new ByteBuffer_IO(tempBytes.length); -#else - data[level] = ByteBuffer::allocateDirect(tempBytes.length); -#endif // __PS3__ - data[level]->clear(); - data[level]->put(tempBytes); - data[level]->position(0)->limit(tempBytes.length); - - delete [] tempBytes.data; - } - } - - if (immediateUpdate) - { - updateOnGPU(); - } - else - { - updated = false; + data[level]->position(0)->limit(mipSize); } } + + if (immediateUpdate) + updateOnGPU(); + else + updated = false; } else { @@ -184,15 +135,14 @@ Texture::~Texture() { delete rect; - for(int i = 0; i < 10; i++ ) + for(int i = 0; i < m_iMipLevels; i++ ) { - if(data[i] != nullptr) delete data[i]; + delete data[i]; + data[i] = nullptr; } if(glId >= 0) - { glDeleteTextures(glId); - } } const Rect2i *Texture::getRect() @@ -202,160 +152,50 @@ const Rect2i *Texture::getRect() void Texture::fill(const Rect2i *rect, int color) { - // 4J Remove 3D - //if (type == GL_TEXTURE_3D) - //{ - // return; - //} + if (data[0] == nullptr || rect == nullptr) + return; - Rect2i *myRect = new Rect2i(0, 0, width, height); - myRect->intersect(rect); - data[0]->position(0); - for (int y = myRect->getY(); y < (myRect->getY() + myRect->getHeight()); y++) + Rect2i myRect(0, 0, width, height); + myRect.intersect(rect); + + int startX = myRect.getX(); + int startY = myRect.getY(); + int fillWidth = myRect.getWidth(); + int endY = startY + myRect.getHeight(); + + if (fillWidth <= 0 || startY >= endY) + return; + + BYTE b0 = static_cast((color >> 24) & 0xff); + BYTE b1 = static_cast((color >> 16) & 0xff); + BYTE b2 = static_cast((color >> 8) & 0xff); + BYTE b3 = static_cast((color >> 0) & 0xff); + + unsigned int finalColor = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; + + unsigned int* pixels = (unsigned int*)data[0]->getBuffer(); + + for (int y = startY; y < endY; y++) { - int line = y * width * 4; - for (int x = myRect->getX(); x < (myRect->getX() + myRect->getWidth()); x++) - { - data[0]->put(line + x * 4 + 0, static_cast((color >> 24) & 0x000000ff)); - data[0]->put(line + x * 4 + 1, static_cast((color >> 16) & 0x000000ff)); - data[0]->put(line + x * 4 + 2, static_cast((color >> 8) & 0x000000ff)); - data[0]->put(line + x * 4 + 3, static_cast((color >> 0) & 0x000000ff)); - } + unsigned int* rowStart = pixels + (y * width) + startX; + + std::fill(rowStart, rowStart + fillWidth, finalColor); } - delete myRect; if (immediateUpdate) - { updateOnGPU(); - } else - { updated = false; - } } void Texture::writeAsBMP(const wstring &name) { // 4J Don't need -#if 0 - if (type == GL_TEXTURE_3D) - { - return; - } - - File *outFile = new File(name); - if (outFile.exists()) - { - outFile.delete(); - } - - DataOutputStream *outStream = nullptr; - //try { - outStream = new DataOutputStream(new FileOutputStream(outFile)); - //} catch (IOException e) { - // Unable to open file for writing for some reason - // return; - //} - - //try { - // Write the header - outStream->writeShort((short)0x424d); // 0x0000: ID - 'BM' - int byteSize = width * height * 4 + 54; - outStream->writeByte((BYTE)(byteSize >> 0)); // 0x0002: Raw file size - outStream->writeByte((BYTE)(byteSize >> 8)); - outStream->writeByte((BYTE)(byteSize >> 16)); - outStream->writeByte((BYTE)(byteSize >> 24)); - outStream->writeInt(0); // 0x0006: Reserved - outStream->writeByte(54); // 0x000A: Start of pixel data - outStream->writeByte(0); - outStream->writeByte(0); - outStream->writeByte(0); - outStream->writeByte(40); // 0x000E: Size of secondary header - outStream->writeByte(0); - outStream->writeByte(0); - outStream->writeByte(0); - outStream->writeByte((BYTE)(width >> 0)); // 0x0012: Image width, in pixels - outStream->writeByte((BYTE)(width >> 8)); - outStream->writeByte((BYTE)(width >> 16)); - outStream->writeByte((BYTE)(width >> 24)); - outStream->writeByte((BYTE)(height >> 0)); // 0x0016: Image height, in pixels - outStream->writeByte((BYTE)(height >> 8)); - outStream->writeByte((BYTE)(height >> 16)); - outStream->writeByte((BYTE)(height >> 24)); - outStream->writeByte(1); // 0x001A: Number of color planes, must be 1 - outStream->writeByte(0); - outStream->writeByte(32); // 0x001C: Bit depth (32bpp) - outStream->writeByte(0); - outStream->writeInt(0); // 0x001E: Compression mode (BI_RGB, uncompressed) - int bufSize = width * height * 4; - outStream->writeInt((BYTE)(bufSize >> 0)); // 0x0022: Raw size of bitmap data - outStream->writeInt((BYTE)(bufSize >> 8)); - outStream->writeInt((BYTE)(bufSize >> 16)); - outStream->writeInt((BYTE)(bufSize >> 24)); - outStream->writeInt(0); // 0x0026: Horizontal resolution in ppm - outStream->writeInt(0); // 0x002A: Vertical resolution in ppm - outStream->writeInt(0); // 0x002E: Palette size (0 to match bit depth) - outStream->writeInt(0); // 0x0032: Number of important colors, 0 for all - - // Pixels follow in inverted Y order - BYTE[] bytes = new BYTE[width * height * 4]; - data.position(0); - data.get(bytes); - for (int y = height - 1; y >= 0; y--) - { - int line = y * width * 4; - for (int x = 0; x < width; x++) - { - outStream->writeByte(bytes[line + x * 4 + 2]); - outStream->writeByte(bytes[line + x * 4 + 1]); - outStream->writeByte(bytes[line + x * 4 + 0]); - outStream->writeByte(bytes[line + x * 4 + 3]); - } - } - - outStream->close(); - //} catch (IOException e) { - // Unable to write to the file for some reason - // return; - //} -#endif } void Texture::writeAsPNG(const wstring &filename) { // 4J Don't need -#if 0 - BufferedImage *image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - ByteBuffer *buffer = this->getData(); - BYTE[] bytes = new BYTE[width * height * 4]; - - buffer.position(0); - buffer.get(bytes); - - for (int x = 0; x < width; x++) - { - for (int y = 0; y < height; y++) - { - int pos = (y * width * 4) + x * 4; - int col = 0; - - col |= (bytes[pos + 2] & 0xFF) << 0; - col |= (bytes[pos + 1] & 0xFF) << 8; - col |= (bytes[pos + 0] & 0xFF) << 16; - col |= (bytes[pos + 3] & 0xFF) << 24; - - image.setRGB(x, y, col); - } - } - - data.position(width * height * 4); - - //try { - ImageIO::write(image, L"png", new File(Minecraft.getWorkingDirectory(), filename)); - //} catch (IOException e) { - // e.printStackTrace(); - //} -#endif } void Texture::blit(int x, int y, Texture *source) @@ -365,17 +205,14 @@ void Texture::blit(int x, int y, Texture *source) void Texture::blit(int x, int y, Texture *source, bool rotated) { - // 4J Remove 3D - //if (type == GL_TEXTURE_3D) - //{ - // return; - //} + if (source == nullptr) return; for(unsigned int level = 0; level < m_iMipLevels; ++level) { ByteBuffer *srcBuffer = source->getData(level); - if(srcBuffer == nullptr) break; + if(srcBuffer == nullptr || data[level] == nullptr) + break; int yy = y >> level; int xx = x >> level; @@ -384,210 +221,119 @@ void Texture::blit(int x, int y, Texture *source, bool rotated) int shh = source->getHeight() >> level; int sww = source->getWidth() >> level; - data[level]->position(0); - srcBuffer->position(0); + unsigned int* dstPixels = (unsigned int*)data[level]->getBuffer(); + unsigned int* srcPixels = (unsigned int*)srcBuffer->getBuffer(); -#if defined __PS3__ && !defined DISABLE_SPU_CODE - if(g_texBlitJobQueuePort->hasCompleted()) + if (!rotated) { - // all outstanding blits have completed, so reset to the start of the blit list - g_currentTexBlit = 0; - } - Texture_blit_DataIn& dataIn = g_textureBlitDataIn[g_currentTexBlit]; - g_currentTexBlit++; - if(g_currentTexBlit >= sc_maxTextureBlits) - { - app.DebugPrintf("ran out of tex blit slots, stalling for completion\n"); - g_texBlitJobQueuePort->waitForCompletion(); - g_currentTexBlit = 0; - } - dataIn.pSrcData = srcBuffer->getBuffer(); - dataIn.pDstData = data[level]->getBuffer(); - dataIn.yy = yy; - dataIn.xx = xx; - dataIn.hh = hh; - dataIn.ww = ww; - dataIn.shh = shh; - dataIn.sww = sww; - dataIn.rotated = rotated; - - C4JSpursJob_Texture_blit blitJob(&dataIn); - g_texBlitJobQueuePort->submitJob(&blitJob); -// p.waitForCompletion(); - -#elif __PSVITA__ - unsigned int *src = (unsigned int *) srcBuffer->getBuffer(); - unsigned int *dst = (unsigned int *) data[level]->getBuffer(); - - for (int srcY = 0; srcY < shh; srcY++) - { - int dstY = yy + srcY; - int srcLine = srcY * sww; - int dstLine = dstY * ww; - - if (rotated) + for (int srcY = 0; srcY < shh; srcY++) { - dstY = yy + (shh - srcY); + int dstY = yy + srcY; + + if (dstY < 0 || dstY >= hh) + continue; + + unsigned int* dstRow = dstPixels + (dstY * ww + xx); + unsigned int* srcRow = srcPixels + (srcY * sww); + + memcpy(dstRow, srcRow, sww * sizeof(unsigned int)); } + } + else + { + for (int srcY = 0; srcY < shh; srcY++) + { + int dstY = yy + (shh - srcY); + if (dstY < 0 || dstY >= hh) + continue; - if (!rotated) - { - memcpy(dst + dstLine + xx, src + srcLine, sww * 4); - } - else - { for (int srcX = 0; srcX < sww; srcX++) { - int dstPos = dstLine + (srcX + xx); - int srcPos = srcLine + srcX; + int dstIndex = xx + (srcX * ww) + dstY; + int srcIndex = (srcY * sww) + srcX; - if (rotated) - { - dstPos = (xx + srcX * ww) + dstY; - } - - dst[dstPos] = src[srcPos]; + dstPixels[dstIndex] = srcPixels[srcIndex]; } } } -#else - for (int srcY = 0; srcY < shh; srcY++) - { - int dstY = yy + srcY; - int srcLine = srcY * sww * 4; - int dstLine = dstY * ww * 4; - - if (rotated) - { - dstY = yy + (shh - srcY); - } - - for (int srcX = 0; srcX < sww; srcX++) - { - int dstPos = dstLine + (srcX + xx) * 4; - int srcPos = srcLine + srcX * 4; - - if (rotated) - { - dstPos = (xx + srcX * ww * 4) + dstY * 4; - } - - data[level]->put(dstPos + 0, srcBuffer->get(srcPos + 0)); - data[level]->put(dstPos + 1, srcBuffer->get(srcPos + 1)); - data[level]->put(dstPos + 2, srcBuffer->get(srcPos + 2)); - data[level]->put(dstPos + 3, srcBuffer->get(srcPos + 3)); - } - } - // Don't delete this, as it belongs to the source texture - //delete srcBuffer; -#endif data[level]->position(ww * hh * 4); } if (immediateUpdate) - { updateOnGPU(); - } else - { updated = false; - } } void Texture::transferFromBuffer(intArray buffer) { if (depth == 1) - { return; - } -// #ifdef __PS3__ -// int byteRemapRGBA[] = { 3, 0, 1, 2 }; -// int byteRemapBGRA[] = { 3, 2, 1, 0 }; -// #else + data[0]->position(0); + int byteRemapRGBA[] = { 0, 1, 2, 3 }; int byteRemapBGRA[] = { 2, 1, 0, 3 }; -// #endif + int *byteRemap = ((format == TFMT_BGRA) ? byteRemapBGRA : byteRemapRGBA); - for (int z = 0; z < depth; z++) + int totalPixels = width * height * depth; + + for (int i = 0; i < totalPixels; i++) { - int plane = z * height * width * 4; - for (int y = 0; y < height; y++) - { - int column = plane + y * width * 4; - for (int x = 0; x < width; x++) - { - int texel = column + x * 4; - data[0]->position(0); - data[0]->put(texel + byteRemap[0], static_cast((buffer[texel >> 2] >> 24) & 0xff)); - data[0]->put(texel + byteRemap[1], static_cast((buffer[texel >> 2] >> 16) & 0xff)); - data[0]->put(texel + byteRemap[2], static_cast((buffer[texel >> 2] >> 8) & 0xff)); - data[0]->put(texel + byteRemap[3], static_cast((buffer[texel >> 2] >> 0) & 0xff)); - } - } + int byteIndex = i * 4; + unsigned int pixel = buffer[i]; + + data[0]->put(byteIndex + byteRemap[0], static_cast((pixel >> 24) & 0xff)); + data[0]->put(byteIndex + byteRemap[1], static_cast((pixel >> 16) & 0xff)); + data[0]->put(byteIndex + byteRemap[2], static_cast((pixel >> 8) & 0xff)); + data[0]->put(byteIndex + byteRemap[3], static_cast((pixel >> 0) & 0xff)); } - data[0]->position(width * height * depth * 4); + data[0]->position(totalPixels * 4); updateOnGPU(); } void Texture::transferFromImage(BufferedImage *image) { - // 4J Remove 3D - //if (type == GL_TEXTURE_3D) - //{ - // return; - //} - int imgWidth = image->getWidth(); int imgHeight = image->getHeight(); if (imgWidth > width || imgHeight > height) { - //Minecraft::GetInstance().getLogger().warning("transferFromImage called with a BufferedImage with dimensions (" + - // imgWidth + ", " + imgHeight + ") larger than the Texture dimensions (" + width + - // ", " + height + "). Ignoring."); app.DebugPrintf("transferFromImage called with a BufferedImage with dimensions (%d, %d) larger than the Texture dimensions (%d, %d). Ignoring.\n", imgWidth, imgHeight, width, height); return; } -// #ifdef __PS3__ -// int byteRemapRGBA[] = { 0, 1, 2, 3 }; -// int byteRemapBGRA[] = { 2, 1, 0, 3 }; -// #else -#ifdef _XBOX - int byteRemapRGBA[] = { 0, 1, 2, 3 }; -#else int byteRemapRGBA[] = { 3, 0, 1, 2 }; -#endif int byteRemapBGRA[] = { 3, 2, 1, 0 }; -// #endif - int *byteRemap = ((format == TFMT_BGRA) ? byteRemapBGRA : byteRemapRGBA); - intArray tempPixels = intArray(width * height); + int *byteRemap = ((format == TFMT_BGRA) ? byteRemapBGRA : byteRemapRGBA); + int b0 = byteRemap[0], b1 = byteRemap[1], b2 = byteRemap[2], b3 = byteRemap[3]; + + int totalPixels = width * height; + + intArray tempPixels = intArray(totalPixels); int transparency = image->getTransparency(); image->getRGB(0, 0, width, height, tempPixels, 0, imgWidth); - byteArray tempBytes = byteArray(width * height * 4); - for (int y = 0; y < height; y++) + byteArray tempBytes = byteArray(totalPixels * 4); + + BYTE* dst = tempBytes.data; + int* src = tempPixels.data; + for (int i = 0; i < totalPixels; i++) { - for (int x = 0; x < width; x++) - { - int intIndex = y * width + x; - int byteIndex = intIndex * 4; - - // Pull ARGB bytes into either RGBA or BGRA depending on format - - tempBytes[byteIndex + byteRemap[0]] = static_cast((tempPixels[intIndex] >> 24) & 0xff); - tempBytes[byteIndex + byteRemap[1]] = static_cast((tempPixels[intIndex] >> 16) & 0xff); - tempBytes[byteIndex + byteRemap[2]] = static_cast((tempPixels[intIndex] >> 8) & 0xff); - tempBytes[byteIndex + byteRemap[3]] = static_cast((tempPixels[intIndex] >> 0) & 0xff); - } + // Pull ARGB bytes into either RGBA or BGRA depending on format + unsigned int pixel = src[i]; + dst[b0] = static_cast((pixel >> 24) & 0xff); + dst[b1] = static_cast((pixel >> 16) & 0xff); + dst[b2] = static_cast((pixel >> 8) & 0xff); + dst[b3] = static_cast((pixel >> 0) & 0xff); + dst += 4; } - for(int i = 0; i < 10; i++ ) + for(int i = 0; i < m_iMipLevels; i++ ) { if(data[i] != nullptr) { @@ -597,11 +343,7 @@ void Texture::transferFromImage(BufferedImage *image) } MemSect(51); -#ifdef __PS3__ - data[0] = new ByteBuffer_IO(tempBytes.length); -#else data[0] = ByteBuffer::allocateDirect(tempBytes.length); -#endif // __{S3__ MemSect(0); data[0]->clear(); data[0]->put(tempBytes); @@ -612,93 +354,94 @@ void Texture::transferFromImage(BufferedImage *image) if(mipmapped || image->getData(1) != nullptr) { mipmapped = true; + + int maxMipPixels = (width >> 1) * (height >> 1); + unsigned int *tempData = new unsigned int[maxMipPixels]; + + BYTE* mipBufferData = new BYTE[maxMipPixels * 4]; + for(unsigned int level = 1; level < MAX_MIP_LEVELS; ++level) { int ww = width >> level; int hh = height >> level; + int mipPixels = ww * hh; - byteArray tempBytes = byteArray(ww * hh * 4); - unsigned int *tempData = new unsigned int[ww * hh]; + if (mipPixels == 0) + break; + + int mipLength = mipPixels * 4; + BYTE* mipDst = mipBufferData; if( image->getData( level ) ) { - memcpy( tempData, image->getData( level ), ww * hh * 4); - for (int y = 0; y < hh; y++) + memcpy( tempData, image->getData( level ), mipLength); + for (int i = 0; i < mipPixels; i++) { - for (int x = 0; x < ww; x++) - { - int intIndex = y * ww + x; - int byteIndex = intIndex * 4; - - // Pull ARGB bytes into either RGBA or BGRA depending on format - - tempBytes[byteIndex + byteRemap[0]] = static_cast((tempData[intIndex] >> 24) & 0xff); - tempBytes[byteIndex + byteRemap[1]] = static_cast((tempData[intIndex] >> 16) & 0xff); - tempBytes[byteIndex + byteRemap[2]] = static_cast((tempData[intIndex] >> 8) & 0xff); - tempBytes[byteIndex + byteRemap[3]] = static_cast((tempData[intIndex] >> 0) & 0xff); - } + // Pull ARGB bytes into either RGBA or BGRA depending on format + unsigned int pixel = tempData[i]; + mipDst[b0] = static_cast((pixel >> 24) & 0xff); + mipDst[b1] = static_cast((pixel >> 16) & 0xff); + mipDst[b2] = static_cast((pixel >> 8) & 0xff); + mipDst[b3] = static_cast((pixel >> 0) & 0xff); + mipDst += 4; } } else { int ow = width >> (level - 1); - - for (int x = 0; x < ww; x++) - for (int y = 0; y < hh; y++) + + for (int y = 0; y < hh; y++) + { + for (int x = 0; x < ww; x++) { - unsigned int c0 = data[level - 1]->getInt(((x * 2 + 0) + (y * 2 + 0) * ow) * 4); - unsigned int c1 = data[level - 1]->getInt(((x * 2 + 1) + (y * 2 + 0) * ow) * 4); - unsigned int c2 = data[level - 1]->getInt(((x * 2 + 1) + (y * 2 + 1) * ow) * 4); - unsigned int c3 = data[level - 1]->getInt(((x * 2 + 0) + (y * 2 + 1) * ow) * 4); -#ifndef _XBOX + int baseIndex = (x * 2) + (y * 2) * ow; + + unsigned int c0 = data[level - 1]->getInt((baseIndex) * 4); + unsigned int c1 = data[level - 1]->getInt((baseIndex + 1) * 4); + unsigned int c2 = data[level - 1]->getInt((baseIndex + 1 + ow) * 4); + unsigned int c3 = data[level - 1]->getInt((baseIndex + ow) * 4); + // 4J - convert our RGBA texels to ARGB that crispBlend is expecting c0 = ( ( c0 >> 8 ) & 0x00ffffff ) | ( c0 << 24 ); c1 = ( ( c1 >> 8 ) & 0x00ffffff ) | ( c1 << 24 ); c2 = ( ( c2 >> 8 ) & 0x00ffffff ) | ( c2 << 24 ); c3 = ( ( c3 >> 8 ) & 0x00ffffff ) | ( c3 << 24 ); -#endif - unsigned int col = crispBlend(crispBlend(c0, c1), crispBlend(c2, c3)); - // 4J - and back from ARGB -> RGBA - //col = ( col << 8 ) | (( col >> 24 ) & 0xff); - //tempData[x + y * ww] = col; - unsigned int intIndex = y * ww + x; - unsigned int byteIndex = intIndex * 4; + unsigned int col = crispBlend(crispBlend(c0, c1), crispBlend(c2, c3)); // Pull ARGB bytes into either RGBA or BGRA depending on format - - tempBytes[byteIndex + byteRemap[0]] = static_cast((col >> 24) & 0xff); - tempBytes[byteIndex + byteRemap[1]] = static_cast((col >> 16) & 0xff); - tempBytes[byteIndex + byteRemap[2]] = static_cast((col >> 8) & 0xff); - tempBytes[byteIndex + byteRemap[3]] = static_cast((col >> 0) & 0xff); + mipDst[b0] = static_cast((col >> 24) & 0xff); + mipDst[b1] = static_cast((col >> 16) & 0xff); + mipDst[b2] = static_cast((col >> 8) & 0xff); + mipDst[b3] = static_cast((col >> 0) & 0xff); + mipDst += 4; } + } } MemSect(51); -#ifdef __PS3__ - data[level] = new ByteBuffer_IO(tempBytes.length); -#else - data[level] = ByteBuffer::allocateDirect(tempBytes.length); -#endif // __{S3__ + data[level] = ByteBuffer::allocateDirect(mipLength); MemSect(0); + data[level]->clear(); - data[level]->put(tempBytes); - data[level]->limit(tempBytes.length); - delete [] tempBytes.data; - delete [] tempData; + + byteArray currentMipBytes; + currentMipBytes.data = mipBufferData; + currentMipBytes.length = mipLength; + + data[level]->put(currentMipBytes); + data[level]->limit(mipLength); } + delete [] mipBufferData; + delete [] tempData; } delete [] tempPixels.data; if (immediateUpdate) - { updateOnGPU(); - } else - { updated = false; - } } unsigned int Texture::crispBlend(unsigned int c0, unsigned int c1) @@ -778,115 +521,70 @@ void Texture::setImmediateUpdate(bool immediateUpdate) void Texture::bind(int mipMapIndex) { - // 4J Removed 3D - //if (depth == 1) - //{ - glEnable(GL_TEXTURE_2D); - //} - //else - //{ - // glEnable(GL_TEXTURE_3D); - //} + glEnable(GL_TEXTURE_2D); glActiveTexture(GL_TEXTURE0 + mipMapIndex); glBindTexture(type, glId); if (!updated) - { updateOnGPU(); - } } void Texture::updateOnGPU() { - data[0]->flip(); - if(mipmapped) - { - for (int level = 1; level < m_iMipLevels; level++) + if(data[0] == nullptr) + return; + + data[0]->position(0); + + // 4J Added check so we can differentiate between which RenderManager function to call + if(!m_bInitialised) + { + RenderManager.TextureSetTextureLevels(m_iMipLevels); // 4J added + + RenderManager.TextureData(width,height,data[0]->getBuffer(),0,C4JRender::TEXTURE_FORMAT_RxGyBzAw); + + if(mipmapped) { - if(data[level] == nullptr) break; - - data[level]->flip(); + for (int level = 1; level < m_iMipLevels; level++) + { + if(data[level] == nullptr) + break; + + data[level]->position(0); + + int levelWidth = width >> level; + int levelHeight = height >> level; + + RenderManager.TextureData(levelWidth,levelHeight,data[level]->getBuffer(),level,C4JRender::TEXTURE_FORMAT_RxGyBzAw); + } } + + m_bInitialised = true; } - // 4J remove 3D and 1D - //if (height != 1 && depth != 1) - //{ - // glTexImage3D(type, 0, format, width, height, depth, 0, format, GL_UNSIGNED_BYTE, data); - //} - //else if(height != 1) - //{ - // 4J Added check so we can differentiate between which RenderManager function to call - if(!m_bInitialised) - { - RenderManager.TextureSetTextureLevels(m_iMipLevels); // 4J added + else + { + RenderManager.TextureDataUpdate(0, 0,width,height,data[0]->getBuffer(),0); -#ifdef __PSVITA__ - // AP - replace the dynamic ram buffer to one that points to a newly allocated video ram texture buffer. This means we don't have to memcpy - // the ram based buffer to it any more inside RenderManager.TextureDataUpdate - unsigned char *newData = RenderManager.TextureData(width,height,data[0]->getBuffer(),0,C4JRender::TEXTURE_FORMAT_RxGyBzAw); - ByteBuffer *oldBuffer = data[0]; - data[0] = new ByteBuffer(data[0]->getSize(), (BYTE*) newData); - delete oldBuffer; - newData += width * height * 4; -#else - RenderManager.TextureData(width,height,data[0]->getBuffer(),0,C4JRender::TEXTURE_FORMAT_RxGyBzAw); -#endif - - if(mipmapped) + if(mipmapped) + { + if (RenderManager.TextureGetTextureLevels() > 1) { for (int level = 1; level < m_iMipLevels; level++) { + if(data[level] == nullptr) + break; + + data[level]->position(0); + int levelWidth = width >> level; int levelHeight = height >> level; -#ifdef __PSVITA__ - // AP - replace the dynamic ram buffer to one that points to a newly allocated video ram texture buffer. This means we don't have to memcpy - // the ram based buffer to it any more inside RenderManager.TextureDataUpdate RenderManager.TextureDataUpdate(0, 0,levelWidth,levelHeight,data[level]->getBuffer(),level); - ByteBuffer *oldBuffer = data[level]; - data[level] = new ByteBuffer(data[level]->getSize(), (BYTE*) newData); - delete oldBuffer; - newData += levelWidth * levelHeight * 4; -#else - RenderManager.TextureData(levelWidth,levelHeight,data[level]->getBuffer(),level,C4JRender::TEXTURE_FORMAT_RxGyBzAw); -#endif - } - } - - m_bInitialised = true; - } - else - { -#ifdef _XBOX - RenderManager.TextureDataUpdate(data[0]->getBuffer(),0); -#else - RenderManager.TextureDataUpdate(0, 0,width,height,data[0]->getBuffer(),0); -#endif - - if(mipmapped) - { - if (RenderManager.TextureGetTextureLevels() > 1) - { - for (int level = 1; level < m_iMipLevels; level++) - { - int levelWidth = width >> level; - int levelHeight = height >> level; - -#ifdef _XBOX - RenderManager.TextureDataUpdate(data[level]->getBuffer(),level); -#else - RenderManager.TextureDataUpdate(0, 0,levelWidth,levelHeight,data[level]->getBuffer(),level); -#endif - } } } } - //glTexImage2D(type, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); - //} - //else - //{ - // glTexImage1D(type, 0, format, width, 0, format, GL_UNSIGNED_BYTE, data); - //} + } + updated = true; } diff --git a/Minecraft.World/Entity.cpp b/Minecraft.World/Entity.cpp index 52b6c18f..c4b9b168 100644 --- a/Minecraft.World/Entity.cpp +++ b/Minecraft.World/Entity.cpp @@ -737,26 +737,42 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - double d = 0.05; while (xa != 0 && level->getCubes(shared, bb->cloneMove(xa, -1.0, 0))->empty()) { - if (xa < d && xa >= -d) xa = 0; - else if (xa > 0) xa -= d; - else xa += d; + if (xa < d && xa >= -d) + xa = 0; + else if (xa > 0) + xa -= d; + else + xa += d; + xaOrg = xa; } while (za != 0 && level->getCubes(shared, bb->cloneMove(0, -1.0, za))->empty()) { - if (za < d && za >= -d) za = 0; - else if (za > 0) za -= d; - else za += d; + if (za < d && za >= -d) + za = 0; + else if (za > 0) + za -= d; + else + za += d; + zaOrg = za; } while (xa != 0 && za != 0 && level->getCubes(shared, bb->cloneMove(xa, -1.0, za))->empty()) { - if (xa < d && xa >= -d) xa = 0; - else if (xa > 0) xa -= d; - else xa += d; - if (za < d && za >= -d) za = 0; - else if (za > 0) za -= d; - else za += d; + if (xa < d && xa >= -d) + xa = 0; + else if (xa > 0) + xa -= d; + else + xa += d; + + if (za < d && za >= -d) + za = 0; + else if (za > 0) + za -= d; + else + za += d; + xaOrg = xa; zaOrg = za; } @@ -771,36 +787,30 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - { // 4J Stu - It's horrible that the client is doing any movement at all! But if we don't have the chunk // data then all the collision info will be incorrect as well - for ( auto& it : *aABBs ) + for ( const auto& it : *aABBs ) ya = it->clipYCollide(bb, ya); bb->move(0, ya, 0); } if (!slide && yaOrg != ya) - { xa = ya = za = 0; - } bool og = onGround || (yaOrg != ya && yaOrg < 0); - for ( auto& it : *aABBs ) + for ( const auto& it : *aABBs ) xa = it->clipXCollide(bb, xa); bb->move(xa, 0, 0); if (!slide && xaOrg != xa) - { xa = ya = za = 0; - } - for ( auto& it : *aABBs ) + for ( const auto& it : *aABBs ) za = it->clipZCollide(bb, za); bb->move(0, 0, za); if (!slide && zaOrg != za) - { xa = ya = za = 0; - } if (footSize > 0 && og && (isPlayerSneaking || ySlideOffset < 0.05f) && ((xaOrg != xa) || (zaOrg != za))) { @@ -822,45 +832,35 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - { // 4J Stu - It's horrible that the client is doing any movement at all! But if we don't have the chunk // data then all the collision info will be incorrect as well - for ( auto& it : *aABBs ) + for ( const auto& it : *aABBs ) ya = it->clipYCollide(bb, ya); bb->move(0, ya, 0); } if (!slide && yaOrg != ya) - { xa = ya = za = 0; - } - - for ( auto& it : *aABBs ) + for ( const auto& it : *aABBs ) xa = it->clipXCollide(bb, xa); bb->move(xa, 0, 0); if (!slide && xaOrg != xa) - { xa = ya = za = 0; - } - for ( auto& it : *aABBs ) + for ( const auto& it : *aABBs ) za = it->clipZCollide(bb, za); bb->move(0, 0, za); if (!slide && zaOrg != za) - { xa = ya = za = 0; - } - if (!slide && yaOrg != ya) - { xa = ya = za = 0; - } else { ya = -footSize; // LAND FIRST, then x and z - for ( auto& it : *aABBs ) + for ( const auto& it : *aABBs ) ya = it->clipYCollide(bb, ya); bb->move(0, ya, 0); } @@ -874,7 +874,6 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - } } - x = (bb->x0 + bb->x1) / 2.0f; y = bb->y0 + heightOffset - ySlideOffset; z = (bb->z0 + bb->z1) / 2.0f; @@ -885,15 +884,17 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - collision = horizontalCollision || verticalCollision; checkFallDamage(ya, onGround); - if (xaOrg != xa) xd = 0; - if (yaOrg != ya) yd = 0; - if (zaOrg != za) zd = 0; + if (xaOrg != xa) + xd = 0; + if (yaOrg != ya) + yd = 0; + if (zaOrg != za) + zd = 0; double xm = x - xo; double ym = y - yo; double zm = z - zo; - if (makeStepSound() && !isPlayerSneaking && riding == nullptr) { int xt = Mth::floor(x); @@ -904,14 +905,10 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - { int renderShape = level->getTileRenderShape(xt, yt - 1, zt); if (renderShape == Tile::SHAPE_FENCE || renderShape == Tile::SHAPE_WALL || renderShape == Tile::SHAPE_FENCE_GATE) - { t = level->getTile(xt, yt - 1, zt); - } } if (t != Tile::ladder_Id) - { ym = 0; - } walkDist += Mth::sqrt(xm * xm + zm * zm) * 0.6; moveDist += Mth::sqrt(xm * xm + ym * ym + zm * zm) * 0.6; @@ -940,15 +937,14 @@ void Entity::move(double xa, double ya, double za, bool noEntityCubes) // 4J - if (!water) { onFire++; - if (onFire == 0) setOnFire(8); + if (onFire == 0) + setOnFire(8); } } else { if (onFire <= 0) - { onFire = -flameTime; - } } if (water && onFire > 0) @@ -967,22 +963,24 @@ void Entity::checkInsideTiles() int y1 = Mth::floor(bb->y1 - 0.001); int z1 = Mth::floor(bb->z1 - 0.001); - if (level->hasChunksAt(x0, y0, z0, x1, y1, z1)) + if (!level->hasChunksAt(x0, y0, z0, x1, y1, z1)) + return; + + auto shared = shared_from_this(); + for (int x = x0; x <= x1; x++) { - for (int x = x0; x <= x1; x++) - for (int y = y0; y <= y1; y++) - for (int z = z0; z <= z1; z++) - { - int t = level->getTile(x, y, z); - if (t > 0) - { - Tile::tiles[t]->entityInside(level, x, y, z, shared_from_this()); - } - } + for (int y = y0; y <= y1; y++) + { + for (int z = z0; z <= z1; z++) + { + int t = level->getTile(x, y, z); + if (t > 0) + Tile::tiles[t]->entityInside(level, x, y, z, shared); + } + } } } - void Entity::playStepSound(int xt, int yt, int zt, int t) { const Tile::SoundType *soundType = Tile::tiles[t]->soundType; @@ -994,10 +992,7 @@ void Entity::playStepSound(int xt, int yt, int zt, int t) unsigned int uiAnimOverrideBitmask=getAnimOverrideBitmask(); // this is masked for custom anim off, and force anim if(( uiAnimOverrideBitmask& (1<getTile(xt, yt + 1, zt) == Tile::topSnow_Id) { @@ -1032,10 +1027,8 @@ void Entity::checkFallDamage(double ya, bool onGround) fallDistance = 0; } } - else - { - if (ya < 0) fallDistance -= static_cast(ya); - } + else if (ya < 0) + fallDistance -= static_cast(ya); } AABB *Entity::getCollideBox() @@ -1046,9 +1039,7 @@ AABB *Entity::getCollideBox() void Entity::burn(int dmg) { if (!fireImmune) - { hurt(DamageSource::inFire, dmg); - } } bool Entity::isFireImmune() @@ -1061,7 +1052,6 @@ void Entity::causeFallDamage(float distance) if (rider.lock() != nullptr) rider.lock()->causeFallDamage(distance); } - bool Entity::isInWaterOrRain() { return wasInWater || (level->isRainingAt( Mth::floor(x), Mth::floor(y), Mth::floor(z)) || level->isRainingAt(Mth::floor(x), Mth::floor(y + bbHeight), Mth::floor(z))); diff --git a/Minecraft.World/McRegionChunkStorage.cpp b/Minecraft.World/McRegionChunkStorage.cpp index dd725b06..35cdc511 100644 --- a/Minecraft.World/McRegionChunkStorage.cpp +++ b/Minecraft.World/McRegionChunkStorage.cpp @@ -10,6 +10,11 @@ std::deque McRegionChunkStorage::s_chunkDataQueue; int McRegionChunkStorage::s_runningThreadCount = 0; C4JThread *McRegionChunkStorage::s_saveThreads[3]; +static bool s_running = true; +static std::mutex s_queue; +static std::condition_variable s_queueC; +static std::condition_variable s_waitC; +static std::condition_variable s_allSavedC; McRegionChunkStorage::McRegionChunkStorage(ConsoleSaveFile *saveFile, const wstring &prefix) : m_prefix( prefix ) { @@ -65,9 +70,17 @@ McRegionChunkStorage::McRegionChunkStorage(ConsoleSaveFile *saveFile, const wstr McRegionChunkStorage::~McRegionChunkStorage() { for(auto& it : m_entityData) - { delete it.second.data; - } + + { + std::lock_guard lock(s_queue); + s_running = false; + } + + s_queueC.notify_all(); + s_waitC.notify_all(); + s_allSavedC.notify_all(); + WaitForAllSaves(); } LevelChunk *McRegionChunkStorage::load(Level *level, int x, int z) @@ -193,9 +206,12 @@ void McRegionChunkStorage::save(Level *level, LevelChunk *levelChunk) PIXEndNamedEvent(); PIXBeginNamedEvent(0,"Updating chunk queue"); - EnterCriticalSection(&cs_memory); - s_chunkDataQueue.push_back(output); - LeaveCriticalSection(&cs_memory); + { + std::lock_guard lock(s_queue); + s_chunkDataQueue.push_back(output); + } + + s_queueC.notify_one(); PIXEndNamedEvent(); } else @@ -333,7 +349,6 @@ void McRegionChunkStorage::staticCtor() //saveThreads[j] = CreateThread(nullptr,0,runSaveThreadProc,&threadData[j],CREATE_SUSPENDED,&threadId[j]); s_saveThreads[i] = new C4JThread(runSaveThreadProc,nullptr,threadName); - //app.DebugPrintf("Created new thread: %s\n",threadName); // Threads 1,3 and 5 are generally idle so use them @@ -356,43 +371,42 @@ int McRegionChunkStorage::runSaveThreadProc(LPVOID lpParam) { Compression::CreateNewThreadStorage(); - bool running = true; - size_t lastQueueSize = 0; - DataOutputStream *dos = nullptr; - while(running) + while(s_running) { - if( TryEnterCriticalSection(&cs_memory) ) { - lastQueueSize = s_chunkDataQueue.size(); - if(lastQueueSize > 0) - { - dos = s_chunkDataQueue.front(); - s_chunkDataQueue.pop_front(); - } - s_runningThreadCount++; - LeaveCriticalSection(&cs_memory); + std::unique_lock lock(s_queue); + + s_queueC.wait(lock, []{return !s_chunkDataQueue.empty() || !s_running;}); + + if (!s_running && s_chunkDataQueue.empty()) + break; + + dos = s_chunkDataQueue.front(); + s_chunkDataQueue.pop_front(); + s_runningThreadCount++; + s_waitC.notify_all(); + } + + if(dos) + { + PIXBeginNamedEvent(0,"Saving chunk"); + //app.DebugPrintf("Compressing chunk data (%d left)\n", lastQueueSize - 1); + dos->close(); + dos->deleteChildStream(); + PIXEndNamedEvent(); - if(dos) - { - PIXBeginNamedEvent(0,"Saving chunk"); - //app.DebugPrintf("Compressing chunk data (%d left)\n", lastQueueSize - 1); - dos->close(); - dos->deleteChildStream(); - PIXEndNamedEvent(); - } delete dos; dos = nullptr; - - EnterCriticalSection(&cs_memory); - s_runningThreadCount--; - LeaveCriticalSection(&cs_memory); } - // If there was more than one thing in the queue last time we checked, then we want to spin round again soon - // Otherwise wait a bit longer - if( (lastQueueSize -1) > 0) Sleep(1); // Sleep 1 to yield - else Sleep(100); + { + std::lock_guard lock(s_queue); + s_runningThreadCount--; + + if (s_chunkDataQueue.empty() && s_runningThreadCount == 0) + s_allSavedC.notify_all(); + } } Compression::ReleaseThreadStorage(); @@ -413,33 +427,10 @@ void McRegionChunkStorage::WaitIfTooManyQueuedChunks() // Static void McRegionChunkStorage::WaitForAllSaves() { - // Wait for there to be no more tasks to be processed... - EnterCriticalSection(&cs_memory); - size_t queueSize = s_chunkDataQueue.size(); - LeaveCriticalSection(&cs_memory); + // Wait for there to be no more tasks or threads to be processed... + std::unique_lock lock(s_queue); - while(queueSize > 0) - { - Sleep(10); - - EnterCriticalSection(&cs_memory); - queueSize = s_chunkDataQueue.size(); - LeaveCriticalSection(&cs_memory); - } - - // And then wait for there to be no running threads that are processing these tasks - EnterCriticalSection(&cs_memory); - int runningThreadCount = s_runningThreadCount; - LeaveCriticalSection(&cs_memory); - - while(runningThreadCount > 0) - { - Sleep(10); - - EnterCriticalSection(&cs_memory); - runningThreadCount = s_runningThreadCount; - LeaveCriticalSection(&cs_memory); - } + s_allSavedC.wait(lock, [] {return s_chunkDataQueue.empty() && (s_runningThreadCount == 0);}); } // Static @@ -449,19 +440,8 @@ void McRegionChunkStorage::WaitForSaves() static const int DESIRED_QUEUE_SIZE = 6; // Wait for the queue to reduce to a level where we should add more elements - EnterCriticalSection(&cs_memory); - size_t queueSize = s_chunkDataQueue.size(); - LeaveCriticalSection(&cs_memory); + std::unique_lock lock(s_queue); - if( queueSize > MAX_QUEUE_SIZE ) - { - while( queueSize > DESIRED_QUEUE_SIZE ) - { - Sleep(10); - - EnterCriticalSection(&cs_memory); - queueSize = s_chunkDataQueue.size(); - LeaveCriticalSection(&cs_memory); - } - } + if( s_chunkDataQueue.size() > MAX_QUEUE_SIZE ) + s_waitC.wait(lock, [] {return s_chunkDataQueue.size() <= DESIRED_QUEUE_SIZE;}); } diff --git a/Minecraft.World/McRegionChunkStorage.h b/Minecraft.World/McRegionChunkStorage.h index 47ae1c99..4fcd6aa4 100644 --- a/Minecraft.World/McRegionChunkStorage.h +++ b/Minecraft.World/McRegionChunkStorage.h @@ -6,6 +6,7 @@ using namespace std; #include "RegionFileCache.h" #include "com.mojang.nbt.h" #include "OldChunkStorage.h" +#include class ConsoleSaveFile;