/* 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. */ /* Modifications Copyright 2003-2004 Bytonic Software Copyright 2010 Google Inc. */ package com.googlecode.gwtquake.shared.render; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.util.Arrays; import java.util.HashMap; import com.googlecode.gwtquake.shared.client.Window; import com.googlecode.gwtquake.shared.common.Com; import com.googlecode.gwtquake.shared.common.ConsoleVariables; import com.googlecode.gwtquake.shared.common.Constants; import com.googlecode.gwtquake.shared.common.Globals; import com.googlecode.gwtquake.shared.common.QuakeImage; import com.googlecode.gwtquake.shared.game.ConsoleVariable; import com.googlecode.gwtquake.shared.util.Lib; import com.googlecode.gwtquake.shared.util.Vargs; /** * Image * * @author cwei */ public abstract class Images { static int waitingForImages = 0; static Image draw_chars; static Image[] gltextures = new Image[GlConstants.MAX_GLTEXTURES]; //Map gltextures = new Hashtable(MAX_GLTEXTURES); // image_t static int numgltextures; static int base_textureid; // gltextures[i] = base_textureid+i static byte[] intensitytable = new byte[256]; static byte[] gammatable = new byte[256]; static ConsoleVariable intensity; // // qboolean GL_Upload8 (byte *data, int width, int height, qboolean mipmap, qboolean is_sky ); // qboolean GL_Upload32 (unsigned *data, int width, int height, qboolean mipmap); // static int gl_solid_format = 3; static int gl_alpha_format = 4; static int gl_tex_solid_format = 3; static int gl_tex_alpha_format = 4; static int gl_filter_min = Gl1Context.GL_LINEAR;//GLAdapter.GL_LINEAR_MIPMAP_NEAREST; static int gl_filter_max = Gl1Context.GL_LINEAR; static { // init the texture cache for (int i = 0; i < gltextures.length; i++) { gltextures[i] = new Image(i); } numgltextures = 0; } static void GL_SetTexturePalette(int[] palette) { assert(palette != null && palette.length == 256) : "int palette[256] bug"; //int i; //byte[] temptable = new byte[768]; // TODO(jgw) // if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f) // { // ByteBuffer temptable=BufferUtils.createByteBuffer(768); // for (i = 0; i < 256; i++) { // temptable.put(i * 3 + 0, (byte) ((palette[i] >> 0) & 0xff)); // temptable.put(i * 3 + 1, (byte) ((palette[i] >> 8) & 0xff)); // temptable.put(i * 3 + 2, (byte) ((palette[i] >> 16) & 0xff)); // } // // gl.glColorTable(EXTSharedTexturePalette.GL_SHARED_TEXTURE_PALETTE_EXT, GLAdapter.GL_RGB, 256, GLAdapter.GL_RGB, GLAdapter.GL_UNSIGNED_BYTE, temptable); // } } static void GL_EnableMultitexture(boolean enable) { if (enable) { GL_SelectTexture(Gl1Context.GL_TEXTURE1); GlState.gl.glEnable(Gl1Context.GL_TEXTURE_2D); GL_TexEnv(Gl1Context.GL_REPLACE); } else { GL_SelectTexture(Gl1Context.GL_TEXTURE1); GlState.gl.glDisable(Gl1Context.GL_TEXTURE_2D); GL_TexEnv(Gl1Context.GL_REPLACE); } GL_SelectTexture(Gl1Context.GL_TEXTURE0); GL_TexEnv(Gl1Context.GL_REPLACE); } static void GL_SelectTexture(int texture /* GLenum */) { int tmu; tmu = (texture == Gl1Context.GL_TEXTURE0) ? 0 : 1; if (tmu == GlConfig.gl_state.currenttmu) { return; } GlConfig.gl_state.currenttmu = tmu; GlState.gl.glActiveTexture(texture); GlState.gl.glClientActiveTexture(texture); } static int[] lastmodes = { -1, -1 }; public static void GL_TexEnv(int mode /* GLenum */ ) { if (mode != lastmodes[GlConfig.gl_state.currenttmu]) { GlState.gl.glTexEnvi(Gl1Context.GL_TEXTURE_ENV, Gl1Context.GL_TEXTURE_ENV_MODE, mode); lastmodes[GlConfig.gl_state.currenttmu] = mode; } } public static void GL_Bind(int texnum) { if ((GlConfig.gl_nobind.value != 0) && (draw_chars != null)) { // performance evaluation option texnum = draw_chars.texnum; } if (GlConfig.gl_state.currenttextures[GlConfig.gl_state.currenttmu] == texnum) return; GlConfig.gl_state.currenttextures[GlConfig.gl_state.currenttmu] = texnum; GlState.gl.glBindTexture(Gl1Context.GL_TEXTURE_2D, texnum); } static void GL_MBind(int target /* GLenum */, int texnum) { GL_SelectTexture(target); if (target == Gl1Context.GL_TEXTURE0) { if (GlConfig.gl_state.currenttextures[0] == texnum) return; } else { if (GlConfig.gl_state.currenttextures[1] == texnum) return; } GL_Bind(texnum); } // glmode_t static class glmode_t { String name; int minimize, maximize; glmode_t(String name, int minimize, int maximze) { this.name = name; this.minimize = minimize; this.maximize = maximze; } } static final glmode_t modes[] = { new glmode_t("GL_NEAREST", Gl1Context.GL_NEAREST, Gl1Context.GL_NEAREST), new glmode_t("GL_LINEAR", Gl1Context.GL_LINEAR, Gl1Context.GL_LINEAR), new glmode_t("GL_NEAREST_MIPMAP_NEAREST", Gl1Context.GL_NEAREST_MIPMAP_NEAREST, Gl1Context.GL_NEAREST), new glmode_t("GL_LINEAR_MIPMAP_NEAREST", Gl1Context.GL_LINEAR_MIPMAP_NEAREST, Gl1Context.GL_LINEAR), new glmode_t("GL_NEAREST_MIPMAP_LINEAR", Gl1Context.GL_NEAREST_MIPMAP_LINEAR, Gl1Context.GL_NEAREST), new glmode_t("GL_LINEAR_MIPMAP_LINEAR", Gl1Context.GL_LINEAR_MIPMAP_LINEAR, Gl1Context.GL_LINEAR)}; static final int NUM_GL_MODES = modes.length; // gltmode_t static class gltmode_t { String name; int mode; gltmode_t(String name, int mode) { this.name = name; this.mode = mode; } } static final gltmode_t[] gl_alpha_modes = { new gltmode_t("default", 4), new gltmode_t("GL_RGBA", Gl1Context.GL_RGBA), // new gltmode_t("GL_RGBA8", GL11.GL_RGBA8), // new gltmode_t("GL_RGB5_A1", GL11.GL_RGB5_A1), // new gltmode_t("GL_RGBA4", GL11.GL_RGBA4), // new gltmode_t("GL_RGBA2", GL11.GL_RGBA2), }; static final int NUM_GL_ALPHA_MODES = gl_alpha_modes.length; static final gltmode_t[] gl_solid_modes = { new gltmode_t("default", 3), new gltmode_t("GL_RGB", Gl1Context.GL_RGB), // new gltmode_t("GL_RGB8", GL11.GL_RGB8), // new gltmode_t("GL_RGB5", GL11.GL_RGB5), // new gltmode_t("GL_RGB4", GL11.GL_RGB4), // new gltmode_t("GL_R3_G3_B2", GL11.GL_R3_G3_B2), // #ifdef GL_RGB2_EXT //new gltmode_t("GL_RGB2", GL11.GL_RGB2_EXT) // #endif }; static final int NUM_GL_SOLID_MODES = gl_solid_modes.length; /* =============== GL_TextureMode =============== */ static void GL_TextureMode(String string) { int i; for (i = 0; i < NUM_GL_MODES; i++) { if (modes[i].name.equalsIgnoreCase(string)) break; } if (i == NUM_GL_MODES) { Window.Printf(Constants.PRINT_ALL, "bad filter name: [" + string + "]\n"); return; } gl_filter_min = modes[i].minimize; gl_filter_max = modes[i].maximize; Image glt; // change all the existing mipmap texture objects for (i = 0; i < numgltextures; i++) { glt = gltextures[i]; if (glt.type != QuakeImage.it_pic && glt.type != QuakeImage.it_sky) { GL_Bind(glt.texnum); GlState.gl.glTexParameterf(Gl1Context.GL_TEXTURE_2D, Gl1Context.GL_TEXTURE_MIN_FILTER, gl_filter_min); GlState.gl.glTexParameterf(Gl1Context.GL_TEXTURE_2D, Gl1Context.GL_TEXTURE_MAG_FILTER, gl_filter_max); } } } /* =============== GL_TextureAlphaMode =============== */ static void GL_TextureAlphaMode(String string) { int i; for (i = 0; i < NUM_GL_ALPHA_MODES; i++) { if (gl_alpha_modes[i].name.equalsIgnoreCase(string)) break; } if (i == NUM_GL_ALPHA_MODES) { Window.Printf(Constants.PRINT_ALL, "bad alpha texture mode name: [" + string + "]\n"); return; } gl_tex_alpha_format = gl_alpha_modes[i].mode; } /* =============== GL_TextureSolidMode =============== */ static void GL_TextureSolidMode(String string) { int i; for (i = 0; i < NUM_GL_SOLID_MODES; i++) { if (gl_solid_modes[i].name.equalsIgnoreCase(string)) break; } if (i == NUM_GL_SOLID_MODES) { Window.Printf(Constants.PRINT_ALL, "bad solid texture mode name: [" + string + "]\n"); return; } gl_tex_solid_format = gl_solid_modes[i].mode; } /* =============== GL_ImageList_f =============== */ static void GL_ImageList_f() { Image image; int texels; final String[] palstrings = { "RGB", "PAL" }; Window.Printf(Constants.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 QuakeImage.it_skin : Window.Printf(Constants.PRINT_ALL, "M"); break; case QuakeImage.it_sprite : Window.Printf(Constants.PRINT_ALL, "S"); break; case QuakeImage.it_wall : Window.Printf(Constants.PRINT_ALL, "W"); break; case QuakeImage.it_pic : Window.Printf(Constants.PRINT_ALL, "P"); break; default : Window.Printf(Constants.PRINT_ALL, " "); break; } Window.Printf( Constants.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)); } Window.Printf(Constants.PRINT_ALL, "Total texel count (not counting mipmaps): " + texels + '\n'); } static class pos_t { int x, y; pos_t(int x, int y) { this.x = x; this.y = y; } } /* ================================================================= PCX LOADING ================================================================= */ // private Throwable gotoBreakOut = new Throwable(); // private Throwable gotoDone = gotoBreakOut; static class floodfill_t { short x, y; } // void FLOODFILL_STEP( int off, int dx, int dy ) // { // if (pos[off] == fillcolor) // { // pos[off] = 255; // fifo[inpt].x = x + dx; fifo[inpt].y = y + dy; // inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; // } // else if (pos[off] != 255) fdc = pos[off]; // } static floodfill_t[] fifo = new floodfill_t[GlConstants.FLOODFILL_FIFO_SIZE]; static { for (int j = 0; j < fifo.length; j++) { fifo[j] = new floodfill_t(); } } // TODO check this: R_FloodFillSkin( byte[] skin, int skinwidth, int skinheight) static void R_FloodFillSkin(byte[] skin, int skinwidth, int skinheight) { // byte fillcolor = *skin; // assume this is the pixel to fill int fillcolor = skin[0] & 0xff; // floodfill_t[] fifo = new floodfill_t[FLOODFILL_FIFO_SIZE]; int inpt = 0, outpt = 0; int filledcolor = -1; int i; // for (int j = 0; j < fifo.length; j++) { // fifo[j] = new floodfill_t(); // } if (filledcolor == -1) { filledcolor = 0; // attempt to find opaque black for (i = 0; i < 256; ++i) // TODO check this if (QuakeImage.PALETTE_ABGR[i] == 0xFF000000) { // alpha 1.0 //if (d_8to24table[i] == (255 << 0)) // 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) & GlConstants.FLOODFILL_FIFO_MASK; while (outpt != inpt) { int x = fifo[outpt].x; int y = fifo[outpt].y; int fdc = filledcolor; // byte *pos = &skin[x + skinwidth * y]; int pos = x + skinwidth * y; // outpt = (outpt + 1) & GlConstants.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) & GlConstants.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) & GlConstants.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) & GlConstants.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) & GlConstants.FLOODFILL_FIFO_MASK; } else if (skin[pos + off] != (byte) 255) fdc = skin[pos + off] & 0xff; } skin[x + skinwidth * y] = (byte) fdc; } } public static final int MAX_NAME_SIZE = Constants.MAX_QPATH; // ======================================================= /* ================ GL_ResampleTexture ================ */ // cwei :-) abstract protected void GL_ResampleTexture(int[] in, int inwidth, int inheight, int[] out, int outwidth, int outheight); /* ================ GL_LightScaleTexture Scale up the pixel values in a texture to increase the lighting range ================ */ 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); } } } /* ============= Draw_FindPic ============= */ protected static Image findPicture(String name) { Image image = null; String fullname; if (!name.startsWith("/") && !name.startsWith("\\")) { fullname = "pics/" + name + ".pcx"; } else { fullname = name.substring(1); } image = findTexture(fullname, QuakeImage.it_pic); return image; } /* ================ GL_MipMap Operates in place, quartering the size of the texture ================ */ static 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); } } } static int upload_width; static int upload_height; /* =============== GL_Upload32 Returns has_alpha =============== */ private static int[] scaled = new int[256 * 256]; //byte[] paletted_texture = new byte[256 * 256]; // ByteBuffer paletted_texture; private static IntBuffer tex = Lib.newIntBuffer(512 * 256, ByteOrder.LITTLE_ENDIAN); static HashMap<String,Image> imageMap = new HashMap<String,Image>(); static boolean GL_Upload32(int[] data, int width, int height, boolean mipmap) { int samples; int scaled_width, scaled_height; int i, c; int comp; Arrays.fill(scaled, 0); // Arrays.fill(paletted_texture, (byte)0); // paletted_texture.clear(); // for (int j=0; j<256*256; j++) paletted_texture.put(j,(byte)0); for (scaled_width = 1; scaled_width < width; scaled_width <<= 1); if (GlConfig.gl_round_down.value > 0.0f && scaled_width > width && mipmap) scaled_width >>= 1; for (scaled_height = 1; scaled_height < height; scaled_height <<= 1); if (GlConfig.gl_round_down.value > 0.0f && scaled_height > height && mipmap) scaled_height >>= 1; // let people sample down the world textures for speed if (mipmap) { scaled_width >>= (int) GlConfig.gl_picmip.value; scaled_height >>= (int) GlConfig.gl_picmip.value; } // don't ever bother with >256 textures if (scaled_width > 256) scaled_width = 256; if (scaled_height > 256) scaled_height = 256; if (scaled_width < 1) scaled_width = 1; if (scaled_height < 1) scaled_height = 1; upload_width = scaled_width; upload_height = scaled_height; if (scaled_width * scaled_height > 256 * 256) Com.Error(Constants.ERR_DROP, "GL_Upload32: too big"); // scan the texture for any non-255 alpha c = width * height; samples = gl_solid_format; for (i = 0; i < c; i++) { if ((data[i] & 0xff000000) != 0xff000000) { samples = gl_alpha_format; break; } } if (samples == gl_solid_format) comp = gl_tex_solid_format; else if (samples == gl_alpha_format) comp = gl_tex_alpha_format; else { Window.Printf(Constants.PRINT_ALL, "Unknown number of texture components " + samples + '\n'); comp = samples; } // simulates a goto try { if (scaled_width == width && scaled_height == height) { if (!mipmap) { // if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && samples == gl_solid_format) { // uploaded_paletted = true; // GL_BuildPalettedTexture(paletted_texture, data, scaled_width, scaled_height); // gl.glTexImage2D( // GLAdapter.GL_TEXTURE_2D, // 0, // GL_COLOR_INDEX8_EXT, // scaled_width, // scaled_height, // 0, // GL11.GL_COLOR_INDEX, // GLAdapter.GL_UNSIGNED_BYTE, // paletted_texture); // } // else { tex.rewind(); tex.put(data); tex.rewind(); GlState.gl.glTexImage2D( Gl1Context.GL_TEXTURE_2D, 0, Gl1Context.GL_RGBA/*comp*/, scaled_width, scaled_height, 0, Gl1Context.GL_RGBA, Gl1Context.GL_UNSIGNED_BYTE, tex); // } //goto done; throw new Exception("goto done"); } //memcpy (scaled, data, width*height*4); were bytes System.arraycopy(data, 0, scaled, 0, width * height); } else Globals.re.GL_ResampleTexture(data, width, height, scaled, scaled_width, scaled_height); // GL_LightScaleTexture(scaled, scaled_width, scaled_height, !mipmap); // if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && (samples == gl_solid_format)) { // uploaded_paletted = true; // GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height); // gl.glTexImage2D( // GLAdapter.GL_TEXTURE_2D, // 0, // GL_COLOR_INDEX8_EXT, // scaled_width, // scaled_height, // 0, // GL11.GL_COLOR_INDEX, // GLAdapter.GL_UNSIGNED_BYTE, // paletted_texture); // } // else { tex.rewind(); tex.put(scaled); tex.rewind(); GlState.gl.glTexImage2D(Gl1Context.GL_TEXTURE_2D, 0, Gl1Context.GL_RGBA/*comp*/, scaled_width, scaled_height, 0, Gl1Context.GL_RGBA, Gl1Context.GL_UNSIGNED_BYTE, tex); // } if (mipmap) { int miplevel; miplevel = 0; while (scaled_width > 1 || scaled_height > 1) { GL_MipMap(scaled, scaled_width, scaled_height); scaled_width >>= 1; scaled_height >>= 1; if (scaled_width < 1) scaled_width = 1; if (scaled_height < 1) scaled_height = 1; miplevel++; // if (qglColorTableEXT && gl_ext_palettedtexture.value != 0.0f && samples == gl_solid_format) { // uploaded_paletted = true; // GL_BuildPalettedTexture(paletted_texture, scaled, scaled_width, scaled_height); // gl.glTexImage2D( // GLAdapter.GL_TEXTURE_2D, // miplevel, // GL_COLOR_INDEX8_EXT, // scaled_width, // scaled_height, // 0, // GL11.GL_COLOR_INDEX, // GLAdapter.GL_UNSIGNED_BYTE, // paletted_texture); // } // else { tex.rewind(); tex.put(scaled); tex.rewind(); GlState.gl.glTexImage2D( Gl1Context.GL_TEXTURE_2D, miplevel, Gl1Context.GL_RGBA/*comp*/, scaled_width, scaled_height, 0, Gl1Context.GL_RGBA, Gl1Context.GL_UNSIGNED_BYTE, tex); // } } } // label done: } catch (Throwable e) { // replaces label done } if (mipmap) { GlState.gl.glTexParameterf(Gl1Context.GL_TEXTURE_2D, Gl1Context.GL_TEXTURE_MIN_FILTER, gl_filter_min); GlState.gl.glTexParameterf(Gl1Context.GL_TEXTURE_2D, Gl1Context.GL_TEXTURE_MAG_FILTER, gl_filter_max); } else { GlState.gl.glTexParameterf(Gl1Context.GL_TEXTURE_2D, Gl1Context.GL_TEXTURE_MIN_FILTER, gl_filter_max); GlState.gl.glTexParameterf(Gl1Context.GL_TEXTURE_2D, Gl1Context.GL_TEXTURE_MAG_FILTER, gl_filter_max); } return (samples == gl_alpha_format); } /* =============== GL_Upload8 Returns has_alpha =============== */ static boolean GL_Upload8(byte[] data, int width, int height, boolean mipmap, boolean is_sky) { return GL_Upload32(QuakeImage.applyPalette(data, width, height, QuakeImage.PALETTE_ABGR), width, height, mipmap); } public final static Image GL_Find_free_image_t(String name, int type) { Image 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 == GlConstants.MAX_GLTEXTURES) Com.Error (Constants.ERR_DROP, "MAX_GLTEXTURES"); numgltextures++; } image = gltextures[i]; if (name.length() > Constants.MAX_QPATH) Com.Error(Constants.ERR_DROP, "Draw_LoadPic: \"" + name + "\" is too long"); image.name = name; image.type = type; image.registration_sequence = GlState.registration_sequence; image.width = image.upload_width = 32; image.height = image.upload_height = 32; image.complete = false; image.texnum = GlConstants.TEXNUM_IMAGES + image.getId(); GL_Bind(image.texnum); return image; } static Image GL_LoadPic(String name, byte[] pic, int width, int height, int type, int bits) { Image image = GL_Find_free_image_t(name, type); image.setData(pic, width, height, bits); return image; } /* =============== GL_FindImage Finds or loads the given image =============== */ static Image findTexture(String name, int type) { // // 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; // Com.Error (ERR_DROP, "GL_FindImage: NULL name"); // Com.Error (ERR_DROP, "GL_FindImage: bad name: %s", name); // look for it Image image = imageMap.get(name); if (image != null && name.equals(image.name)) { image.registration_sequence = GlState.registration_sequence; return image; } image = Globals.re.GL_LoadNewImage(name, type); imageMap.put(name, image); return image; } /* static ModelImage GL_LoadNewImage(String name, int type) { // // load the pic from disk // ModelImage image = null; byte[] pic = null; Dimension dim = new Dimension(); // // load the file // byte[] raw = QuakeFileSystem.LoadFile(name); if (raw == null) { Window.Printf(Constants.PRINT_ALL, "GL_FindImage: can't load " + name + '\n'); return GlState.r_notexture; } if (name.endsWith(".pcx")) { pic = QuakeImage.LoadPCX(raw, null, dim); image = GL_LoadPic(name, pic, dim.width, dim.height, type, 8); } else if (name.endsWith(".wal")) { pic = QuakeImage.GL_LoadWal(raw, dim); image = GL_LoadPic(name, pic, dim.width, dim.height, type, 8); } else if (name.endsWith(".tga")) { pic = QuakeImage.LoadTGA(raw, dim); if (pic == null) return null; image = GL_LoadPic(name, pic, dim.width, dim.height, type, 32); } else throw new RuntimeException("unknow image type!"); return image; } */ /* =============== R_RegisterSkin =============== */ protected static Image R_RegisterSkin(String name) { return findTexture(name, QuakeImage.it_skin); } static IntBuffer texnumBuffer; static void init() { // paletted_texture = gl.createByteBuffer(256*256); texnumBuffer=Lib.newIntBuffer(1); } /* ================ GL_FreeUnusedImages Any image that was not touched on this registration sequence will be freed. ================ */ static void GL_FreeUnusedImages() { // never free r_notexture or particle texture GlState.r_notexture.registration_sequence = GlState.registration_sequence; GlState.r_particletexture.registration_sequence = GlState.registration_sequence; Image image = null; for (int i = 0; i < numgltextures; i++) { image = gltextures[i]; // used this sequence if (image.registration_sequence == GlState.registration_sequence) continue; // free image_t slot if (image.registration_sequence == 0) continue; // don't free pics if (image.type == QuakeImage.it_pic) continue; // free it // TODO jogl bug texnumBuffer.clear(); texnumBuffer.put(0,image.texnum); GlState.gl.glDeleteTextures(texnumBuffer); image.clear(); } } /* =============== Draw_GetPalette =============== */ protected static void Draw_GetPalette() { // HACK(jgw): This used to load from pics/colormap.pcx, but it was a pain to // do this correctly without a sync load, and I see no evidence that this // colormap ever changes. // d_8to24table = new int[] { ... } (this is now set directly in the static initializer) Particles.setColorPalette(QuakeImage.PALETTE_ABGR); } /* =============== GL_InitImages =============== */ static void GL_InitImages() { int i, j; float g = GlConfig.vid_gamma.value; GlState.registration_sequence = 1; // init intensity conversions intensity = ConsoleVariables.Get("intensity", "2", 0); if (intensity.value <= 1) ConsoleVariables.Set("intensity", "1"); GlConfig.gl_state.inverse_intensity = 1 / intensity.value; Draw_GetPalette(); 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_ShutdownImages =============== */ static void GL_ShutdownImages() { Image image; for (int i=0; i < numgltextures ; i++) { image = gltextures[i]; if (image.registration_sequence == 0) continue; // free image_t slot // free it // TODO jogl bug texnumBuffer.clear(); texnumBuffer.put(0,image.texnum); GlState.gl.glDeleteTextures(texnumBuffer); image.clear(); } } }