/* Copyright (C) 1997-2001 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Created on 20.08.2006 by RST. // $Id: Image.java,v 1.1 2006-10-31 13:06:32 salomo Exp $ package jake2.render.common; import jake2.Defines; import jake2.client.VID; import jake2.client.particle_t; import jake2.game.cvar_t; import jake2.qcommon.*; import jake2.render.image_t; import jake2.util.Vargs; import java.awt.Dimension; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; public abstract class Image extends Main { public static class pos_t { public int x, y; public pos_t(int x, int y) { this.x = x; this.y = y; } } public static class floodfill_t { public short x, y; } protected static final int MAX_SCRAPS = 1; protected static final int BLOCK_WIDTH = 256; protected static final int BLOCK_HEIGHT = 256; protected int[][] scrap_allocated = new int[MAX_SCRAPS][BLOCK_WIDTH]; protected byte[][] scrap_texels = new byte[MAX_SCRAPS][BLOCK_WIDTH * BLOCK_HEIGHT]; protected boolean scrap_dirty; // must be a power of 2 protected static final int FLOODFILL_FIFO_SIZE = 0x1000; protected static final int FLOODFILL_FIFO_MASK = FLOODFILL_FIFO_SIZE - 1; protected static floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; static { for (int j = 0; j < fifo.length; j++) { fifo[j] = new floodfill_t(); } } // gltmode_t public static class gltmode_t { public String name; public int mode; public gltmode_t(String name, int mode) { this.name = name; this.mode = mode; } } // glmode_t public static class glmode_t { public String name; public int minimize, maximize; public glmode_t(String name, int minimize, int maximze) { this.name = name; this.minimize = minimize; this.maximize = maximze; } } protected glmode_t[] getGLModes() { return new glmode_t[]{ new glmode_t("GL_NEAREST", ggl.GL_NEAREST, ggl.GL_NEAREST), new glmode_t("GL_LINEAR", ggl.GL_LINEAR, ggl.GL_LINEAR), new glmode_t("GL_NEAREST_MIPMAP_NEAREST", ggl.GL_NEAREST_MIPMAP_NEAREST, ggl.GL_NEAREST), new glmode_t("GL_LINEAR_MIPMAP_NEAREST", ggl.GL_LINEAR_MIPMAP_NEAREST, ggl.GL_LINEAR), new glmode_t("GL_NEAREST_MIPMAP_LINEAR", ggl.GL_NEAREST_MIPMAP_LINEAR, ggl.GL_NEAREST), new glmode_t("GL_LINEAR_MIPMAP_LINEAR", ggl.GL_LINEAR_MIPMAP_LINEAR, ggl.GL_LINEAR) }; } protected gltmode_t[] getGLAlphaModes() { return new gltmode_t[] { new gltmode_t("default", 4), new gltmode_t("GL_RGBA", ggl.GL_RGBA), new gltmode_t("GL_RGBA8", ggl.GL_RGBA8), new gltmode_t("GL_RGB5_A1", ggl.GL_RGB5_A1), new gltmode_t("GL_RGBA4", ggl.GL_RGBA4), new gltmode_t("GL_RGBA2", ggl.GL_RGBA2) }; } protected gltmode_t[] getGLSolidModes() { return new gltmode_t[] { new gltmode_t("default", 3), new gltmode_t("GL_RGB", ggl.GL_RGB), new gltmode_t("GL_RGB8", ggl.GL_RGB8), new gltmode_t("GL_RGB5", ggl.GL_RGB5), new gltmode_t("GL_RGB4", ggl.GL_RGB4), new gltmode_t("GL_R3_G3_B2", ggl.GL_R3_G3_B2), //new gltmode_t("GL_RGB2", GL.GL_RGB2_EXT); }; } protected image_t draw_chars; protected image_t[] gltextures = new image_t[MAX_GLTEXTURES]; protected int numgltextures; protected int base_textureid; // gltextures[i] = base_textureid+i protected byte[] intensitytable = new byte[256]; protected byte[] gammatable = new byte[256]; protected cvar_t intensity; public Image() { // init the texture cache for (int i = 0; i < gltextures.length; i++) { gltextures[i] = new image_t(i); } numgltextures = 0; } protected int gl_solid_format = 3; protected int gl_alpha_format = 4; protected int gl_tex_solid_format = 3; protected int gl_tex_alpha_format = 4; protected int gl_filter_min = ggl.GL_LINEAR_MIPMAP_NEAREST; protected int gl_filter_max = ggl.GL_LINEAR; protected int upload_width, upload_height; protected boolean uploaded_paletted; /** * GL_TextureAlphaMode */ protected void GL_TextureAlphaMode(String string) { int i; gltmode_t [] gl_alpha_modes = getGLAlphaModes(); for (i = 0; i < gl_alpha_modes.length ; i++) { if (gl_alpha_modes[i].name.equalsIgnoreCase(string)) break; } if (i == gl_alpha_modes.length) { VID.Printf(Defines.PRINT_ALL, "bad alpha texture mode name: [" + string + "]\n"); return; } gl_tex_alpha_format = gl_alpha_modes[i].mode; } /** * GL_TextureSolidMode */ protected void GL_TextureSolidMode(String string) { int i; gltmode_t [] gl_solid_modes = getGLAlphaModes(); for (i = 0; i < gl_solid_modes.length; i++) { if (gl_solid_modes[i].name.equalsIgnoreCase(string)) break; } if (i == gl_solid_modes.length) { VID.Printf(Defines.PRINT_ALL, "bad solid texture mode name: [" + string + "]\n"); return; } gl_tex_solid_format = gl_solid_modes[i].mode; } /** * GL_TextureMode */ protected void GL_TextureMode(String string) { int i; glmode_t modes [] = getGLModes(); for (i = 0; i < modes.length; i++) { if (modes[i].name.equalsIgnoreCase(string)) break; } if (i == modes.length) { VID.Printf(Defines.PRINT_ALL, "bad filter name: [" + string + "]\n"); return; } gl_filter_min = modes[i].minimize; gl_filter_max = modes[i].maximize; image_t glt; // change all the existing mipmap texture objects for (i = 0; i < numgltextures; i++) { glt = gltextures[i]; if (glt.type != it_pic && glt.type != it_sky) { GL_Bind(glt.texnum); ggl.glTexParameteri(ggl.GL_TEXTURE_2D, ggl.GL_TEXTURE_MIN_FILTER, gl_filter_min); ggl.glTexParameteri(ggl.GL_TEXTURE_2D, ggl.GL_TEXTURE_MAG_FILTER, gl_filter_max); } } } protected void GL_EnableMultitexture(boolean enable) { if (enable) { GL_SelectTexture(GL_TEXTURE1); ggl.glEnable(ggl.GL_TEXTURE_2D); GL_TexEnv(ggl.GL_REPLACE); } else { GL_SelectTexture(GL_TEXTURE1); ggl.glDisable(ggl.GL_TEXTURE_2D); GL_TexEnv(ggl.GL_REPLACE); } GL_SelectTexture(GL_TEXTURE0); GL_TexEnv(ggl.GL_REPLACE); } protected void GL_SelectTexture(int texture) { int tmu; tmu = (texture == GL_TEXTURE0) ? 0 : 1; if (tmu == gl_state.currenttmu) { return; } gl_state.currenttmu = tmu; ggl.glActiveTextureARB(texture); ggl.glClientActiveTextureARB(texture); } int[] lastmodes = { -1, -1 }; protected void GL_TexEnv(int mode) { if (mode != lastmodes[gl_state.currenttmu]) { ggl.glTexEnvi(ggl.GL_TEXTURE_ENV, ggl.GL_TEXTURE_ENV_MODE, mode); lastmodes[gl_state.currenttmu] = mode; } } /** * GL_ImageList_f */ protected void GL_ImageList_f() { image_t image; int texels; final String[] palstrings = { "RGB", "PAL" }; VID.Printf(Defines.PRINT_ALL, "------------------\n"); texels = 0; for (int i = 0; i < numgltextures; i++) { image = gltextures[i]; if (image.texnum <= 0) continue; texels += image.upload_width * image.upload_height; switch (image.type) { case it_skin: VID.Printf(Defines.PRINT_ALL, "M"); break; case it_sprite: VID.Printf(Defines.PRINT_ALL, "S"); break; case it_wall: VID.Printf(Defines.PRINT_ALL, "W"); break; case it_pic: VID.Printf(Defines.PRINT_ALL, "P"); break; default: VID.Printf(Defines.PRINT_ALL, " "); break; } VID.Printf(Defines.PRINT_ALL, " %3i %3i %s: %s\n", new Vargs(4).add(image.upload_width). add(image.upload_height).add(palstrings[(image.paletted) ? 1 : 0]).add(image.name)); } VID.Printf(Defines.PRINT_ALL, "Total texel count (not counting mipmaps): " + texels + '\n'); } /* * ============================================================================= * * scrap allocation * * Allocate all the little status bar objects into a single texture to * crutch up inefficient hardware / drivers * * ============================================================================= */ /** * Returns a texture number and the position inside it. */ protected int Scrap_AllocBlock(int w, int h, pos_t pos) { int i, j; int best, best2; int texnum; for (texnum = 0; texnum < MAX_SCRAPS; texnum++) { best = BLOCK_HEIGHT; for (i = 0; i < BLOCK_WIDTH - w; i++) { best2 = 0; for (j = 0; j < w; j++) { if (scrap_allocated[texnum][i + j] >= best) break; if (scrap_allocated[texnum][i + j] > best2) best2 = scrap_allocated[texnum][i + j]; } if (j == w) { // this is a valid spot pos.x = i; pos.y = best = best2; } } if (best + h > BLOCK_HEIGHT) continue; for (i = 0; i < w; i++) scrap_allocated[texnum][pos.x + i] = best + h; return texnum; } return -1; } /** * Mod_FloodFillSkin * * Fill background pixels so mipmapping doesn't have haloes */ // TODO check this protected void R_FloodFillSkin(byte[] skin, int skinwidth, int skinheight) { // assume this is the pixel to fill int fillcolor = skin[0] & 0xFF; int inpt = 0, outpt = 0; int filledcolor = -1; int i; if (filledcolor == -1) { filledcolor = 0; // attempt to find opaque black for (i = 0; i < 256; ++i) if (d_8to24table[i] == 0xFF000000) { // alpha // 1.0 filledcolor = i; break; } } // can't fill to filled color or to transparent color (used as visited // marker) if ((fillcolor == filledcolor) || (fillcolor == 255)) { return; } fifo[inpt].x = 0; fifo[inpt].y = 0; inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; while (outpt != inpt) { int x = fifo[outpt].x; int y = fifo[outpt].y; int fdc = filledcolor; int pos = x + skinwidth * y; // outpt = (outpt + 1) & FLOODFILL_FIFO_MASK; int off, dx, dy; if (x > 0) { // FLOODFILL_STEP( -1, -1, 0 ); off = -1; dx = -1; dy = 0; if (skin[pos + off] == (byte) fillcolor) { skin[pos + off] = (byte) 255; fifo[inpt].x = (short) (x + dx); fifo[inpt].y = (short) (y + dy); inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; } else if (skin[pos + off] != (byte) 255) fdc = skin[pos + off] & 0xff; } if (x < skinwidth - 1) { // FLOODFILL_STEP( 1, 1, 0 ); off = 1; dx = 1; dy = 0; if (skin[pos + off] == (byte) fillcolor) { skin[pos + off] = (byte) 255; fifo[inpt].x = (short) (x + dx); fifo[inpt].y = (short) (y + dy); inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; } else if (skin[pos + off] != (byte) 255) fdc = skin[pos + off] & 0xff; } if (y > 0) { // FLOODFILL_STEP( -skinwidth, 0, -1 ); off = -skinwidth; dx = 0; dy = -1; if (skin[pos + off] == (byte) fillcolor) { skin[pos + off] = (byte) 255; fifo[inpt].x = (short) (x + dx); fifo[inpt].y = (short) (y + dy); inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; } else if (skin[pos + off] != (byte) 255) fdc = skin[pos + off] & 0xff; } if (y < skinheight - 1) { // FLOODFILL_STEP( skinwidth, 0, 1 ); off = skinwidth; dx = 0; dy = 1; if (skin[pos + off] == (byte) fillcolor) { skin[pos + off] = (byte) 255; fifo[inpt].x = (short) (x + dx); fifo[inpt].y = (short) (y + dy); inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; } else if (skin[pos + off] != (byte) 255) fdc = skin[pos + off] & 0xff; } skin[x + skinwidth * y] = (byte) fdc; } } /** * GL_ResampleTexture, simplified by cwei. */ protected void GL_ResampleTexture(int[] in, int inwidth, int inheight, int[] out, int outwidth, int outheight) { BufferedImage image = new BufferedImage(inwidth, inheight, BufferedImage.TYPE_INT_ARGB); image.setRGB(0, 0, inwidth, inheight, in, 0, inwidth); AffineTransformOp op = new AffineTransformOp( AffineTransform.getScaleInstance(outwidth * 1.0 / inwidth, outheight * 1.0 / inheight), AffineTransformOp.TYPE_NEAREST_NEIGHBOR); BufferedImage tmp = op.filter(image, null); tmp.getRGB(0, 0, outwidth, outheight, out, 0, outwidth); } /** * GL_LightScaleTexture, Scale up the pixel values in a texture to increase the lighting range. */ protected void GL_LightScaleTexture(int[] in, int inwidth, int inheight, boolean only_gamma) { if (only_gamma) { int i, c; int r, g, b, color; c = inwidth * inheight; for (i = 0; i < c; i++) { color = in[i]; r = (color >> 0) & 0xFF; g = (color >> 8) & 0xFF; b = (color >> 16) & 0xFF; r = gammatable[r] & 0xFF; g = gammatable[g] & 0xFF; b = gammatable[b] & 0xFF; in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); } } else { int i, c; int r, g, b, color; c = inwidth * inheight; for (i = 0; i < c; i++) { color = in[i]; r = (color >> 0) & 0xFF; g = (color >> 8) & 0xFF; b = (color >> 16) & 0xFF; r = gammatable[intensitytable[r] & 0xFF] & 0xFF; g = gammatable[intensitytable[g] & 0xFF] & 0xFF; b = gammatable[intensitytable[b] & 0xFF] & 0xFF; in[i] = (r << 0) | (g << 8) | (b << 16) | (color & 0xFF000000); } } } /** * GL_MipMap * * Operates in place, quartering the size of the texture */ protected void GL_MipMap(int[] in, int width, int height) { int i, j; int[] out; out = in; int inIndex = 0; int outIndex = 0; int r, g, b, a; int p1, p2, p3, p4; for (i = 0; i < height; i += 2, inIndex += width) { for (j = 0; j < width; j += 2, outIndex += 1, inIndex += 2) { p1 = in[inIndex + 0]; p2 = in[inIndex + 1]; p3 = in[inIndex + width + 0]; p4 = in[inIndex + width + 1]; r = (((p1 >> 0) & 0xFF) + ((p2 >> 0) & 0xFF) + ((p3 >> 0) & 0xFF) + ((p4 >> 0) & 0xFF)) >> 2; g = (((p1 >> 8) & 0xFF) + ((p2 >> 8) & 0xFF) + ((p3 >> 8) & 0xFF) + ((p4 >> 8) & 0xFF)) >> 2; b = (((p1 >> 16) & 0xFF) + ((p2 >> 16) & 0xFF) + ((p3 >> 16) & 0xFF) + ((p4 >> 16) & 0xFF)) >> 2; a = (((p1 >> 24) & 0xFF) + ((p2 >> 24) & 0xFF) + ((p3 >> 24) & 0xFF) + ((p4 >> 24) & 0xFF)) >> 2; out[outIndex] = (r << 0) | (g << 8) | (b << 16) | (a << 24); } } } /** * GL_InitImages */ protected void GL_InitImages() { int i, j; float g = vid_gamma.value; registration_sequence = 1; // init intensity conversions intensity = Cvar.Get("intensity", "2", 0); if (intensity.value <= 1) Cvar.Set("intensity", "1"); gl_state.inverse_intensity = 1 / intensity.value; Draw_GetPalette(); if (qglColorTableEXT) { gl_state.d_16to8table = FS.LoadFile("pics/16to8.dat"); if (gl_state.d_16to8table == null) Com.Error(Defines.ERR_FATAL, "Couldn't load pics/16to8.pcx"); } if ((gl_config.renderer & (GL_RENDERER_VOODOO | GL_RENDERER_VOODOO2)) != 0) { g = 1.0F; } for (i = 0; i < 256; i++) { if (g == 1.0f) { gammatable[i] = (byte) i; } else { int inf = (int) (255.0f * Math.pow((i + 0.5) / 255.5, g) + 0.5); if (inf < 0) inf = 0; if (inf > 255) inf = 255; gammatable[i] = (byte) inf; } } for (i = 0; i < 256; i++) { j = (int) (i * intensity.value); if (j > 255) j = 255; intensitytable[i] = (byte) j; } } /** * GL_LoadPic * This is also used as an entry point for the generated r_notexture. */ protected image_t GL_LoadPic(String name, byte[] pic, int width, int height, int type, int bits) { image_t image; int i; // find a free image_t for (i = 0; i < numgltextures; i++) { image = gltextures[i]; if (image.texnum == 0) break; } if (i == numgltextures) { if (numgltextures == MAX_GLTEXTURES) Com.Error(Defines.ERR_DROP, "MAX_GLTEXTURES"); numgltextures++; } image = gltextures[i]; if (name.length() > Defines.MAX_QPATH) Com.Error(Defines.ERR_DROP, "Draw_LoadPic: \"" + name + "\" is too long"); image.name = name; image.registration_sequence = registration_sequence; image.width = width; image.height = height; image.type = type; if (type == it_skin && bits == 8) R_FloodFillSkin(pic, width, height); // load little pics into the scrap if (image.type == it_pic && bits == 8 && image.width < 64 && image.height < 64) { pos_t pos = new pos_t(0, 0); int j, k; int texnum = Scrap_AllocBlock(image.width, image.height, pos); if (texnum == -1) { // replace goto nonscrap image.scrap = false; image.texnum = TEXNUM_IMAGES + image.getId(); // image pos in // array GL_Bind(image.texnum); if (bits == 8) { image.has_alpha = GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky); } else { int[] tmp = new int[pic.length / 4]; for (i = 0; i < tmp.length; i++) { tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; } image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky)); } image.upload_width = upload_width; // after power of 2 and scales image.upload_height = upload_height; image.paletted = uploaded_paletted; image.sl = 0; image.sh = 1; image.tl = 0; image.th = 1; return image; } scrap_dirty = true; // copy the texels into the scrap block k = 0; for (i = 0; i < image.height; i++) for (j = 0; j < image.width; j++, k++) scrap_texels[texnum][(pos.y + i) * BLOCK_WIDTH + pos.x + j] = pic[k]; image.texnum = TEXNUM_SCRAPS + texnum; image.scrap = true; image.has_alpha = true; image.sl = (pos.x + 0.01f) / (float) BLOCK_WIDTH; image.sh = (pos.x + image.width - 0.01f) / (float) BLOCK_WIDTH; image.tl = (pos.y + 0.01f) / (float) BLOCK_WIDTH; image.th = (pos.y + image.height - 0.01f) / (float) BLOCK_WIDTH; } else { // this was label nonscrap image.scrap = false; image.texnum = TEXNUM_IMAGES + image.getId(); // image pos in // array GL_Bind(image.texnum); if (bits == 8) { image.has_alpha = GL_Upload8(pic, width, height, (image.type != it_pic && image.type != it_sky), image.type == it_sky); } else { int[] tmp = new int[pic.length / 4]; for (i = 0; i < tmp.length; i++) { tmp[i] = ((pic[4 * i + 0] & 0xFF) << 0); // & 0x000000FF; tmp[i] |= ((pic[4 * i + 1] & 0xFF) << 8); // & 0x0000FF00; tmp[i] |= ((pic[4 * i + 2] & 0xFF) << 16); // & 0x00FF0000; tmp[i] |= ((pic[4 * i + 3] & 0xFF) << 24); // & 0xFF000000; } image.has_alpha = GL_Upload32(tmp, width, height, (image.type != it_pic && image.type != it_sky)); } image.upload_width = upload_width; // after power of 2 and scales image.upload_height = upload_height; image.paletted = uploaded_paletted; image.sl = 0; image.sh = 1; image.tl = 0; image.th = 1; } return image; } /** * LoadPCX */ protected byte[] LoadPCX(String filename, byte[][] palette, Dimension dim) { qfiles.pcx_t pcx; // // load the file // byte[] raw = FS.LoadFile(filename); if (raw == null) { VID.Printf(Defines.PRINT_DEVELOPER, "Bad pcx file " + filename + '\n'); return null; } // // parse the PCX file // pcx = new qfiles.pcx_t(raw); if (pcx.manufacturer != 0x0a || pcx.version != 5 || pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcx.xmax >= 640 || pcx.ymax >= 480) { VID.Printf(Defines.PRINT_ALL, "Bad pcx file " + filename + '\n'); return null; } int width = pcx.xmax - pcx.xmin + 1; int height = pcx.ymax - pcx.ymin + 1; byte[] pix = new byte[width * height]; if (palette != null) { palette[0] = new byte[768]; System.arraycopy(raw, raw.length - 768, palette[0], 0, 768); } if (dim != null) { dim.width = width; dim.height = height; } // // decode pcx // int count = 0; byte dataByte = 0; int runLength = 0; int x, y; for (y = 0; y < height; y++) { for (x = 0; x < width;) { dataByte = pcx.data.get(); if ((dataByte & 0xC0) == 0xC0) { runLength = dataByte & 0x3F; dataByte = pcx.data.get(); // write runLength pixel while (runLength-- > 0) { pix[count++] = dataByte; x++; } } else { // write one pixel pix[count++] = dataByte; x++; } } } return pix; } protected Throwable gotoBreakOut = new Throwable(); protected Throwable gotoDone = gotoBreakOut; // /* // ========================================================= // // TARGA LOADING // // ========================================================= // */ /** * LoadTGA */ protected byte[] LoadTGA(String name, Dimension dim) { int columns, rows, numPixels; int pixbuf; // index into pic int row, column; byte[] raw; ByteBuffer buf_p; qfiles.tga_t targa_header; byte[] pic = null; // // load the file // raw = FS.LoadFile(name); if (raw == null) { VID.Printf(Defines.PRINT_DEVELOPER, "Bad tga file " + name + '\n'); return null; } targa_header = new qfiles.tga_t(raw); if (targa_header.image_type != 2 && targa_header.image_type != 10) Com.Error(Defines.ERR_DROP, "LoadTGA: Only type 2 and 10 targa RGB images supported\n"); if (targa_header.colormap_type != 0 || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) Com.Error(Defines.ERR_DROP, "LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); columns = targa_header.width; rows = targa_header.height; numPixels = columns * rows; if (dim != null) { dim.width = columns; dim.height = rows; } pic = new byte[numPixels * 4]; // targa_rgba; if (targa_header.id_length != 0) targa_header.data.position(targa_header.id_length); // skip TARGA // image comment buf_p = targa_header.data; byte red, green, blue, alphabyte; red = green = blue = alphabyte = 0; int packetHeader, packetSize, j; if (targa_header.image_type == 2) { // Uncompressed, RGB images for (row = rows - 1; row >= 0; row--) { pixbuf = row * columns * 4; for (column = 0; column < columns; column++) { switch (targa_header.pixel_size) { case 24: blue = buf_p.get(); green = buf_p.get(); red = buf_p.get(); pic[pixbuf++] = red; pic[pixbuf++] = green; pic[pixbuf++] = blue; pic[pixbuf++] = (byte) 255; break; case 32: blue = buf_p.get(); green = buf_p.get(); red = buf_p.get(); alphabyte = buf_p.get(); pic[pixbuf++] = red; pic[pixbuf++] = green; pic[pixbuf++] = blue; pic[pixbuf++] = alphabyte; break; } } } } else if (targa_header.image_type == 10) { // Runlength encoded RGB images for (row = rows - 1; row >= 0; row--) { pixbuf = row * columns * 4; try { for (column = 0; column < columns;) { packetHeader = buf_p.get() & 0xFF; packetSize = 1 + (packetHeader & 0x7f); if ((packetHeader & 0x80) != 0) { // run-length packet switch (targa_header.pixel_size) { case 24: blue = buf_p.get(); green = buf_p.get(); red = buf_p.get(); alphabyte = (byte) 255; break; case 32: blue = buf_p.get(); green = buf_p.get(); red = buf_p.get(); alphabyte = buf_p.get(); break; } for (j = 0; j < packetSize; j++) { pic[pixbuf++] = red; pic[pixbuf++] = green; pic[pixbuf++] = blue; pic[pixbuf++] = alphabyte; column++; if (column == columns) { // run spans across rows column = 0; if (row > 0) row--; else // goto label breakOut; throw gotoBreakOut; pixbuf = row * columns * 4; } } } else { // non run-length packet for (j = 0; j < packetSize; j++) { switch (targa_header.pixel_size) { case 24: blue = buf_p.get(); green = buf_p.get(); red = buf_p.get(); pic[pixbuf++] = red; pic[pixbuf++] = green; pic[pixbuf++] = blue; pic[pixbuf++] = (byte) 255; break; case 32: blue = buf_p.get(); green = buf_p.get(); red = buf_p.get(); alphabyte = buf_p.get(); pic[pixbuf++] = red; pic[pixbuf++] = green; pic[pixbuf++] = blue; pic[pixbuf++] = alphabyte; break; } column++; if (column == columns) { // pixel packet run // spans across rows column = 0; if (row > 0) row--; else // goto label breakOut; throw gotoBreakOut; pixbuf = row * columns * 4; } } } } } catch (Throwable e) { // label breakOut: } } } return pic; } /** * GL_LoadWal */ protected image_t GL_LoadWal(String name) { image_t image = null; byte[] raw = FS.LoadFile(name); if (raw == null) { VID.Printf(Defines.PRINT_ALL, "GL_FindImage: can't load " + name + '\n'); return r_notexture; } qfiles.miptex_t mt = new qfiles.miptex_t(raw); byte[] pix = new byte[mt.width * mt.height]; System.arraycopy(raw, mt.offsets[0], pix, 0, pix.length); image = GL_LoadPic(name, pix, mt.width, mt.height, it_wall, 8); return image; } /** * GL_FindImage * * Finds or loads the given image. */ protected image_t GL_FindImage(String name, int type) { image_t image = null; // TODO loest das grossschreibungs problem // name = name.toLowerCase(); // bughack for bad strings (fuck \0) // int index = name.indexOf('\0'); // if (index != -1) // name = name.substring(0, index); if (name == null || name.length() < 5) return null; // look for it for (int i = 0; i < numgltextures; i++) { image = gltextures[i]; if (name.equals(image.name)) { image.registration_sequence = registration_sequence; return image; } } // // load the pic from disk // image = null; byte[] pic = null; Dimension dim = new Dimension(); if (name.endsWith(".pcx")) { pic = LoadPCX(name, null, dim); if (pic == null) return null; image = GL_LoadPic(name, pic, dim.width, dim.height, type, 8); } else if (name.endsWith(".wal")) { image = GL_LoadWal(name); } else if (name.endsWith(".tga")) { pic = LoadTGA(name, dim); if (pic == null) return null; image = GL_LoadPic(name, pic, dim.width, dim.height, type, 32); } return image; } /** * R_RegisterSkin */ protected image_t R_RegisterSkin(String name) { return GL_FindImage(name, it_skin); } /** * Draw_GetPalettes */ protected void Draw_GetPalette() { int r, g, b; byte[] pic; byte[][] palette = new byte[1][]; // new byte[768]; // get the palette pic = LoadPCX("pics/colormap.pcx", palette, new Dimension()); if (pic == null || palette[0] == null || palette[0].length != 768) Com.Error(Defines.ERR_FATAL, "Couldn't load pics/colormap.pcx"); byte[] pal = palette[0]; int j = 0; for (int i = 0; i < 256; i++) { r = pal[j++] & 0xFF; g = pal[j++] & 0xFF; b = pal[j++] & 0xFF; d_8to24table[i] = (255 << 24) | (b << 16) | (g << 8) | (r << 0); } d_8to24table[255] &= 0x00FFFFFF; // 255 is transparent particle_t.setColorPalette(d_8to24table); } /** * GL_BuildPalettedTexture. */ protected void GL_BuildPalettedTexture(byte[] paletted_texture, int[] scaled, int scaled_width, int scaled_height) { int r, g, b, c; int size = scaled_width * scaled_height; for (int i = 0; i < size; i++) { r = (scaled[i] >> 3) & 31; g = (scaled[i] >> 10) & 63; b = (scaled[i] >> 19) & 31; c = r | (g << 5) | (b << 11); paletted_texture[i] = gl_state.d_16to8table[c]; } } protected void GL_Bind(int texnum) { if ((gl_nobind.value != 0) && (draw_chars != null)) { // performance evaluation option texnum = draw_chars.texnum; } if (gl_state.currenttextures[gl_state.currenttmu] == texnum) return; gl_state.currenttextures[gl_state.currenttmu] = texnum; ggl.glBindTexture(ggl.GL_TEXTURE_2D, texnum); } int scrap_uploads = 0; protected void Scrap_Upload() { scrap_uploads++; GL_Bind(TEXNUM_SCRAPS); GL_Upload8(scrap_texels[0], BLOCK_WIDTH, BLOCK_HEIGHT, false, false); scrap_dirty = false; } protected void GL_MBind(int target, int texnum) { GL_SelectTexture(target); if (target == GL_TEXTURE0) { if (gl_state.currenttextures[0] == texnum) return; } else { if (gl_state.currenttextures[1] == texnum) return; } GL_Bind(texnum); } }