/* * JaamSim Discrete Event Simulation * Copyright (C) 2012 Ausenco Engineering Canada Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jaamsim.render; import java.nio.ByteBuffer; import java.nio.IntBuffer; public class S3TexCompressor { // These are useful scratch arrays int[] rs = new int[4]; int[] gs = new int[4]; int[] bs = new int[4]; int[] pixels = new int[16]; public ByteBuffer compress(IntBuffer inBuffer, int width, int height) { int blocksWide = ((width + 3) >> 2); int blocksHigh = ((height+3) >> 2); int numBlocks = blocksWide * blocksHigh; ByteBuffer ret = ByteBuffer.allocate(numBlocks * 8); for (int by = 0; by < blocksHigh; ++by) { for (int bx = 0; bx < blocksWide; ++bx) { // Build up a block int x = bx*4; int y = by*4; // Handle being near the right or top edge int maxPX = 3; int maxPY = 3; if (by == blocksHigh - 1 && (height & 3) != 0) { maxPY = (height&3)-1; } if (bx == blocksWide - 1 && (width & 3) != 0) { maxPX = (width&3)-1; } for (int py = 0; py < 4; ++py) { int rpy = py; if (py > maxPY) { rpy = maxPY; } for (int px = 0; px < 4; ++px) { int rpx = px; if (px > maxPX) { rpx = maxPX; } pixels[rpy*4+rpx] = inBuffer.get((y+rpy)*width+x+rpx); } } compressBlock(pixels, ret); } } assert(ret.position() == ret.capacity()); ret.flip(); return ret; } private void compressBlock(int[] pixels, ByteBuffer out) { assert(pixels.length == 16); // Find the extreme colours int minMag = 765; int maxMag = 0; int minR = 0, minG = 0, minB = 0; int maxR = 0, maxG = 0, maxB = 0; for (int i = 0; i < 16; ++i) { int pix = pixels[i]; int r = pix & 0xff; int g = (pix >> 8) & 0xff; int b = (pix >> 16) & 0xff; int mag = r + g + b; if (mag < minMag) { minMag = mag; minR = r; minG = g; minB = b; } if (mag > maxMag) { maxMag = mag; maxR = r; maxG = g; maxB = b; } } int c0 = 0; c0 += (maxB >> 3) << 11; c0 += (maxG >> 2) << 5; c0 += (maxR >> 3); int c1 = 0; c1 += (minB >> 3) << 11; c1 += (minG >> 2) << 5; c1 += (minR >> 3); if (c1 > c0) { // Swap the order int temp = minR; minR = maxR; maxR = temp; temp = minG; minG = maxG; maxG = temp; temp = minB; minB = maxB; maxB = temp; temp = c0; c0 = c1; c1 = temp; } out.put((byte)(c0 & 0xff)); out.put((byte)((c0>>8) & 0xff)); out.put((byte)(c1 & 0xff)); out.put((byte)((c1>>8) & 0xff)); rs[0] = maxR; gs[0] = maxG; bs[0] = maxB; rs[1] = minR; gs[1] = minG; bs[1] = minB; if (c0 == c1) { rs[2] = (maxR+minR)/2; gs[2] = (maxG+minG)/2; bs[2] = (maxB+minB)/2; rs[3] = 0; gs[3] = 0; bs[3] = 0; } else { rs[2] = (2*maxR+minR)/3; gs[2] = (2*maxG+minG)/3; bs[2] = (2*maxB+minB)/3; rs[3] = (maxR+2*minR)/3; gs[3] = (maxG+2*minG)/3; bs[3] = (maxB+2*minB)/3; } int numVals = 0; int outByte = 0; int mult = 1; for (int i = 0; i < 16; ++i) { int pix = pixels[i]; int r = pix & 0xff; int g = (pix >> 8) & 0xff; int b = (pix >> 16) & 0xff; int bestDiff = 756; int bestInd = 0; for (int j = 0; j < 4; ++j) { int diff = Math.abs(r-rs[j]) + Math.abs(g-gs[j]) + Math.abs(b-bs[j]); if (diff < bestDiff) { bestInd = j; bestDiff = diff; } } outByte += bestInd * mult; mult = mult << 2; if (++numVals == 4) { mult = 1; numVals = 0; out.put((byte)outByte); outByte = 0; } } } }