Java tutorial
/* `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.gdxquake2.game.render; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Pixmap; import com.googlecode.gdxquake2.gdxext.AsyncFileHandle; import com.googlecode.gdxquake2.GdxQuake2; import com.googlecode.gdxquake2.gdxext.AsyncPixmapLoader; import com.googlecode.gdxquake2.gl11.GL11; import com.googlecode.gdxquake2.gl11.GLDebug; import com.googlecode.gdxquake2.gl11.MeshBuilder; import com.googlecode.gdxquake2.game.gdxadapter.GdxKbdImpl; import com.googlecode.gdxquake2.game.client.Dimension; import com.googlecode.gdxquake2.game.client.Renderer; import com.googlecode.gdxquake2.game.client.RendererState; import com.googlecode.gdxquake2.game.client.Window; import com.googlecode.gdxquake2.game.common.AsyncCallback; import com.googlecode.gdxquake2.game.common.Com; import com.googlecode.gdxquake2.game.common.ConsoleVariables; import com.googlecode.gdxquake2.game.common.Constants; import com.googlecode.gdxquake2.game.common.ExecutableCommand; import com.googlecode.gdxquake2.game.common.QuakeImage; import com.googlecode.gdxquake2.game.game.Commands; import com.googlecode.gdxquake2.game.game.ConsoleVariable; import com.googlecode.gdxquake2.game.sys.KBD; import com.googlecode.gdxquake2.game.util.Lib; import com.googlecode.gdxquake2.game.util.Vargs; import com.googlecode.gdxquake2.gdxext.Callback; /** * LWJGLRenderer * * @author dsanders/cwei */ public class GlRenderer implements Renderer { static final String TAG = "GlRenderer"; int width; int height; List<Image> pendingImages = new ArrayList<Image>(); public GlRenderer(GL11 gl, int width, int height) { GlState.gl = gl; this.width = width; this.height = height; init(); } public DisplayMode[] getAvailableDisplayModes() { return new DisplayMode[] { getDisplayMode() }; } public DisplayMode getDisplayMode() { return new DisplayMode(width, height); } // ============================================================================ // public interface for Renderer implementations // // refexport_t (ref.h) // ============================================================================ @Override public boolean Init(int vid_xpos, int vid_ypos) { // pre init assert (GlConstants.SIN.length == 256) : "warpsin table bug"; Window.Printf(Constants.PRINT_ALL, "ref_gl version: " + GlConstants.REF_VERSION + '\n'); Images.Draw_GetPalette(); GlConfig.init(); Commands.addCommand("imagelist", new ExecutableCommand() { public void execute() { Images.GL_ImageList_f(); } }); Commands.addCommand("screenshot", new ExecutableCommand() { public void execute() { Misc.GL_ScreenShot_f(); } }); Commands.addCommand("modellist", new ExecutableCommand() { public void execute() { Models.Mod_Modellist_f(); } }); Commands.addCommand("gl_strings", new ExecutableCommand() { public void execute() { Misc.GL_Strings_f(); } }); // set our "safe" modes GlState.prev_mode = 3; // create the window and set up the context if (!R_SetMode()) { Window.Printf(Constants.PRINT_ALL, "ref_gl::R_Init() - could not R_SetMode()\n"); return false; } // post init GlState.qglPointParameterfEXT = true; Misc.GL_SetDefaultState(); Images.GL_InitImages(); Models.Mod_Init(); Particles.R_InitParticleTexture(); Drawing.Draw_InitLocal(); int err = GlState.gl.glGetError(); if (err != GL11.GL_NO_ERROR) { Window.Printf(Constants.PRINT_ALL, "glGetError() = 0x%x\n\t%s\n", new Vargs(2).add(err).add("" + GlState.gl.glGetString(err))); // return false; } return true; } protected void init() { GlState.r_world_matrix = Lib.newFloatBuffer(16); Images.init(); Mesh.init(); Models.init(); } @Override public void Shutdown() { Commands.RemoveCommand("modellist"); Commands.RemoveCommand("screenshot"); Commands.RemoveCommand("imagelist"); Commands.RemoveCommand("gl_strings"); Models.Mod_FreeAll(); Images.GL_ShutdownImages(); /* * shut down OS specific OpenGL stuff like contexts, etc. */ //GlState.gl.shutdow(); } @Override public final void BeginRegistration(String map, Runnable callback) { Models.R_BeginRegistration(map, callback); } @Override public final void RegisterModel(String name, AsyncCallback<Model> callback) { Models.R_RegisterModel(name, callback); } @Override public final Image RegisterSkin(String name) { return Images.R_RegisterSkin(name); } @Override public Image RegisterPic(String name) { return Images.findPicture(name); } @Override public final void SetSky(String name, float rotate, float[] axis) { SkyBox.R_SetSky(name, rotate, axis); } @Override public final void EndRegistration() { Models.R_EndRegistration(); } @Override public final void RenderFrame(RendererState fd) { Entities.R_RenderFrame(fd); } public void DrawChar(int x, int y, int ch) { Images.GL_Bind(Images.draw_chars.texnum); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, MeshBuilder.OPTION_TEXTURE); DrawChar_(x, y, ch); GlState.meshBuilder.end(GlState.gl); } public void DrawString(int x, int y, String str) { DrawString(x, y, str, 0, str.length(), false); } public void DrawString(int x, int y, String str, boolean alt) { DrawString(x, y, str, 0, str.length(), alt); } public final void DrawString(int x, int y, String str, int ofs, int len) { DrawString(x, y, str, ofs, len, false); } public void DrawString(int x, int y, String str, int ofs, int len, boolean alt) { Images.GL_Bind(Images.draw_chars.texnum); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, MeshBuilder.OPTION_TEXTURE); for (int i = 0; i < len; ++i) { DrawChar_(x, y, str.charAt(ofs + i) + (alt ? 128 : 0)); x += 8; } GlState.meshBuilder.end(GlState.gl); } public void DrawString(int x, int y, byte[] str, int ofs, int len) { Images.GL_Bind(Images.draw_chars.texnum); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, MeshBuilder.OPTION_TEXTURE); for (int i = 0; i < len; ++i) { DrawChar_(x, y, str[ofs + i]); x += 8; } GlState.meshBuilder.end(GlState.gl); } /** * @see com.googlecode.gdxquake2.game.client.Renderer#CinematicSetPalette(byte[]) */ public void CinematicSetPalette(byte[] palette) { // 256 RGB values (768 bytes) // or null int i; int color = 0; if (palette != null) { int j = 0; for (i = 0; i < 256; i++) { color = (palette[j++] & 0xFF) << 0; color |= (palette[j++] & 0xFF) << 8; color |= (palette[j++] & 0xFF) << 16; color |= 0xFF000000; GlState.r_rawpalette[i] = color; } } else { for (i = 0; i < 256; i++) { GlState.r_rawpalette[i] = QuakeImage.PALETTE_ABGR[i] | 0xff000000; } } Images.GL_SetTexturePalette(GlState.r_rawpalette); GlState.gl.glClearColor(0, 0, 0, 0); GlState.gl.glClear(GL11.GL_COLOR_BUFFER_BIT); GlState.gl.glClearColor(1f, 0f, 0.5f, 0.5f); } /** * @see com.googlecode.gdxquake2.game.client.Renderer#EndFrame() */ public final void EndFrame() { GlState.gl.glFlush(); //swapBuffers(); // swap buffers } /** * @see com.googlecode.gdxquake2.game.client.Renderer#AppActivate(boolean) */ public final void AppActivate(boolean activate) { } public final int apiVersion() { return Constants.API_VERSION; } public boolean showVideo(String name) { return false; } public boolean updateVideo() { return false; } public void DrawStretchPic(int x, int y, int w, int h, String pic) { Image image; image = Images.findPicture(pic); if (image == null) { Window.Printf(Constants.PRINT_ALL, "Can't find pic: " + pic + '\n'); return; } // if (scrap_dirty) // Scrap_Upload(); // if (!image.has_alpha) { // GlState.gl.glDisable(GL11.GL_ALPHA_TEST); // } Images.GL_Bind(image.texnum); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, MeshBuilder.OPTION_TEXTURE); GlState.meshBuilder.texCoord2f(0, 0); GlState.meshBuilder.vertex2f(x, y); GlState.meshBuilder.texCoord2f(1, 0); GlState.meshBuilder.vertex2f(x + w, y); GlState.meshBuilder.texCoord2f(1, 1); GlState.meshBuilder.vertex2f(x + w, y + h); GlState.meshBuilder.texCoord2f(0, 1); GlState.meshBuilder.vertex2f(x, y + h); GlState.meshBuilder.end(GlState.gl); // if (!image.has_alpha) { // GlState.gl.glEnable(GL11.GL_ALPHA_TEST); // } } public final void DrawGetPicSize(Dimension dim, String pic) { Image image = Images.findPicture(pic); dim.width = (image != null) ? image.width : -1; dim.height = (image != null) ? image.height : -1; } protected void DrawChar_(int x, int y, int num) { num &= 255; if ((num & 127) == 32) return; // space if (y <= -8) return; // totally off screen int row = num >> 4; int col = num & 15; float frow = row * 0.0625f; float fcol = col * 0.0625f; float size = 0.0625f; GlState.meshBuilder.texCoord2f(fcol, frow); GlState.meshBuilder.vertex2f(x, y); GlState.meshBuilder.texCoord2f(fcol + size, frow); GlState.meshBuilder.vertex2f(x + 8, y); GlState.meshBuilder.texCoord2f(fcol + size, frow + size); GlState.meshBuilder.vertex2f(x + 8, y + 8); GlState.meshBuilder.texCoord2f(fcol, frow + size); GlState.meshBuilder.vertex2f(x, y + 8); } /* * ============= Draw_TileClear * * This repeats a 64*64 tile graphic to fill the screen around a sized down * refresh window. ============= */ public final void DrawTileClear(int x, int y, int w, int h, String pic) { Image image; image = Images.findPicture(pic); if (image == null) { Window.Printf(Constants.PRINT_ALL, "Can't find pic: " + pic + '\n'); return; } // if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( (gl_config.renderer // & GL_RENDERER_RENDITION) != 0 ) ) && !image.has_alpha) // gl.glDisable(GLAdapter.GL_ALPHA_TEST); Images.GL_Bind(image.texnum); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, MeshBuilder.OPTION_TEXTURE); GlState.meshBuilder.texCoord2f(x / 64.0f, y / 64.0f); GlState.meshBuilder.vertex2f(x, y); GlState.meshBuilder.texCoord2f((x + w) / 64.0f, y / 64.0f); GlState.meshBuilder.vertex2f(x + w, y); GlState.meshBuilder.texCoord2f((x + w) / 64.0f, (y + h) / 64.0f); GlState.meshBuilder.vertex2f(x + w, y + h); GlState.meshBuilder.texCoord2f(x / 64.0f, (y + h) / 64.0f); GlState.meshBuilder.vertex2f(x, y + h); GlState.meshBuilder.end(GlState.gl); // if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( (gl_config.renderer // & GL_RENDERER_RENDITION) != 0 ) ) && !image.has_alpha) // gl.glEnable(GLAdapter.GL_ALPHA_TEST); } /* * ============= Draw_Fill * * Fills a box of pixels with a single color ============= */ /** * @see com.googlecode.gdxquake2.game.client.Renderer#DrawFill */ public void DrawFill(int x, int y, int w, int h, int colorIndex) { if (colorIndex > 255) Com.Error(Constants.ERR_FATAL, "Draw_Fill: bad color"); GlState.gl.glDisable(GL11.GL_TEXTURE_2D); int color = QuakeImage.PALETTE_ABGR[colorIndex]; GlState.gl.glColor4ub((byte) ((color >> 0) & 0xff), // r (byte) ((color >> 8) & 0xff), // g (byte) ((color >> 16) & 0xff), // b (byte) 255); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, 0); GlState.meshBuilder.vertex2f(x, y); GlState.meshBuilder.vertex2f(x + w, y); GlState.meshBuilder.vertex2f(x + w, y + h); GlState.meshBuilder.vertex2f(x, y + h); GlState.meshBuilder.end(GlState.gl); GlState.gl.glColor4f(1, 1, 1, 1); GlState.gl.glEnable(GL11.GL_TEXTURE_2D); } // ============================================================================= /* * ================ Draw_FadeScreen ================ */ /** * @see com.googlecode.gdxquake2.game.client.Renderer#DrawFadeScreen() */ public void DrawFadeScreen() { GlState.gl.glEnable(GL11.GL_BLEND); GlState.gl.glDisable(GL11.GL_TEXTURE_2D); // GlState.gl.glColor4f(0, 0, 0, 0.8f); GlState.gl.glColor4f(0, 0, 0, 0.666f); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, 0); GlState.meshBuilder.vertex2f(0, 0); GlState.meshBuilder.vertex2f(GlState.vid.width, 0); GlState.meshBuilder.vertex2f(GlState.vid.width, GlState.vid.height); GlState.meshBuilder.vertex2f(0, GlState.vid.height); GlState.meshBuilder.end(GlState.gl); GlState.gl.glColor4f(1, 1, 1, 1); GlState.gl.glEnable(GL11.GL_TEXTURE_2D); GlState.gl.glDisable(GL11.GL_BLEND); } /* * ============= Draw_Pic ============= */ public void DrawPic(int x, int y, String pic) { Image image; image = Images.findPicture(pic); if (image == null) { Window.Printf(Constants.PRINT_ALL, "Can't find pic: " + pic + '\n'); return; } // if (scrap_dirty) // Scrap_Upload(); // if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( (gl_config.renderer // & GL_RENDERER_RENDITION) != 0 ) ) && !image.has_alpha) // gl.glDisable (GLAdapter.GL_ALPHA_TEST); // GlState.gl.glDisable(GL11.GL_ALPHA_TEST); Images.GL_Bind(image.texnum); // GlState.gl.glColor4f(1.f, .5f, .5f, 1f); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, MeshBuilder.OPTION_TEXTURE); GlState.meshBuilder.texCoord2f(0, 0); GlState.meshBuilder.vertex2f(x, y); GlState.meshBuilder.texCoord2f(1, 0); GlState.meshBuilder.vertex2f(x + image.width, y); GlState.meshBuilder.texCoord2f(1, 1); GlState.meshBuilder.vertex2f(x + image.width, y + image.height); GlState.meshBuilder.texCoord2f(0, 1); GlState.meshBuilder.vertex2f(x, y + image.height); GlState.meshBuilder.end(GlState.gl); // if ( ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( (gl_config.renderer // & GL_RENDERER_RENDITION) != 0 ) ) && !image.has_alpha) // gl.glEnable (GLAdapter.GL_ALPHA_TEST); } /* * ============= Draw_StretchRaw ============= */ public final void DrawStretchRaw(int x, int y, int w, int h, int cols, int rows, byte[] data) { int i, j, trows; int sourceIndex; int frac, fracstep; float hscale; int row; float t; Images.GL_Bind(0); if (rows <= 256) { hscale = 1; trows = rows; } else { hscale = rows / 256.0f; trows = 256; } t = rows * hscale / 256; // if ( !qglColorTableEXT ) // { // int[] image32 = new int[256*256]; Drawing.image32.clear(); int destIndex = 0; for (i = 0; i < trows; i++) { row = (int) (i * hscale); if (row > rows) break; sourceIndex = cols * row; destIndex = i * 256; fracstep = cols * 0x10000 / 256; frac = fracstep >> 1; for (j = 0; j < 256; j++) { Drawing.image32.put(destIndex + j, GlState.r_rawpalette[data[sourceIndex + (frac >> 16)] & 0xff]); frac += fracstep; } } GlState.gl.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA/* gl_tex_solid_format */, 256, 256, 0, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, Drawing.image32); // } // else // { // //byte[] image8 = new byte[256*256]; // image8.clear(); // int destIndex = 0;; // // for (i=0 ; i<trows ; i++) // { // row = (int)(i*hscale); // if (row > rows) // break; // sourceIndex = cols*row; // destIndex = i*256; // fracstep = cols*0x10000/256; // frac = fracstep >> 1; // for (j=0 ; j<256 ; j++) // { // image8.put(destIndex + j, data[sourceIndex + (frac>>16)]); // frac += fracstep; // } // } // // gl.glTexImage2D( GLAdapter.GL_TEXTURE_2D, // 0, // GL_COLOR_INDEX8_EXT, // 256, 256, // 0, // GLAdapter._GL_COLOR_INDEX, // GLAdapter.GL_UNSIGNED_BYTE, // image8 ); // } // GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, // GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); // GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, // GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); // if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( (gl_config.renderer & // GL_RENDERER_RENDITION) != 0 ) ) // gl.glDisable (GLAdapter.GL_ALPHA_TEST); GlState.meshBuilder.begin(MeshBuilder.Mode.QUADS, MeshBuilder.OPTION_TEXTURE); GlState.meshBuilder.texCoord2f(0, 0); GlState.meshBuilder.vertex2f(x, y); GlState.meshBuilder.texCoord2f(1, 0); GlState.meshBuilder.vertex2f(x + w, y); GlState.meshBuilder.texCoord2f(1, t); GlState.meshBuilder.vertex2f(x + w, y + h); GlState.meshBuilder.texCoord2f(0, t); GlState.meshBuilder.vertex2f(x, y + h); GlState.meshBuilder.end(GlState.gl); // if ( ( gl_config.renderer == GL_RENDERER_MCD ) || ( (gl_config.renderer & // GL_RENDERER_RENDITION) != 0 ) ) // gl.glEnable (GLAdapter.GL_ALPHA_TEST); } /** * @param dim * @param mode * @param fullscreen * @return enum rserr_t */ public int GLimp_SetMode(Dimension dim, int mode, boolean fullscreen) { // TODO: jgw fullscreen = false; // GlState.gl.log("GLimp_SetMode"); Dimension newDim = new Dimension(dim.width, dim.height); /* * fullscreen handling */ // GlState.gl.log("determining old display mode"); if (GlState.oldDisplayMode == null) { GlState.oldDisplayMode = getDisplayMode(); } // destroy the existing window // GlState.gl.shutdow(); // GlState.gl.log("searching new display mode"); DisplayMode displayMode = DisplayModes.findDisplayMode(newDim); // GlState.gl.log("copying w/h"); newDim.width = displayMode.getWidth(); newDim.height = displayMode.getHeight(); // GlState.gl.log("setting mode: " + displayMode); this.width = newDim.width; this.height = newDim.height; // GlState.gl.log("storing mode"); GlState.vid.width = newDim.width; GlState.vid.height = newDim.height; // let the sound and input subsystems know about the new window // GlState.gl.log("newWindow notification"); Window.NewWindow(GlState.vid.width, GlState.vid.height); return GlConstants.rserr_ok; } /** * R_SetMode */ protected boolean R_SetMode() { boolean fullscreen = (GlConfig.vid_fullscreen.value > 0.0f); GlConfig.vid_fullscreen.modified = false; GlConfig.gl_mode.modified = false; Dimension dim = new Dimension(GlState.vid.width, GlState.vid.height); int err; // enum rserr_t if ((err = GLimp_SetMode(dim, (int) GlConfig.gl_mode.value, fullscreen)) == GlConstants.rserr_ok) { GlConfig.gl_state.prev_mode = (int) GlConfig.gl_mode.value; } else { if (err == GlConstants.rserr_invalid_fullscreen) { ConsoleVariables.SetValue("vid_fullscreen", 0); GlConfig.vid_fullscreen.modified = false; Window.Printf(Constants.PRINT_ALL, "ref_gl::R_SetMode() - fullscreen unavailable in this mode\n"); if ((err = GLimp_SetMode(dim, (int) GlConfig.gl_mode.value, false)) == GlConstants.rserr_ok) return true; } else if (err == GlConstants.rserr_invalid_mode) { ConsoleVariables.SetValue("gl_mode", GlConfig.gl_state.prev_mode); GlConfig.gl_mode.modified = false; Window.Printf(Constants.PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n"); } // try setting it back to something safe if ((err = GLimp_SetMode(dim, GlConfig.gl_state.prev_mode, false)) != GlConstants.rserr_ok) { Window.Printf(Constants.PRINT_ALL, "ref_gl::R_SetMode() - could not revert to safe mode\n"); return false; } } return true; } /** * this is a hack for jogl renderers. * * @param callback */ public final void updateScreen(ExecutableCommand callback) { callback.execute(); } /** * R_BeginFrame */ public final void BeginFrame(float camera_separation) { GlConfig.gl_state.camera_separation = camera_separation; /* * * change modes if necessary */ if (GlConfig.gl_mode.modified || GlConfig.vid_fullscreen.modified) { // FIXME: only restart if CDS is required ConsoleVariable ref; ref = ConsoleVariables.Get("vid_ref", "lwjgl", 0); ref.modified = true; } if (GlConfig.gl_log.modified) { // GlBase.GLimp_EnableLogging((GlState.gl_log.value != 0.0f)); GlConfig.gl_log.modified = false; } if (GlConfig.gl_log.value != 0.0f) { // GlBase.GLimp_LogNewFrame(); } /* * * update 3Dfx gamma -- it is expected that a user will do a vid_restart* * after tweaking this value */ if (GlConfig.vid_gamma.modified) { GlConfig.vid_gamma.modified = false; } /* * * go into 2D mode */ GlState.gl.glViewport(0, 0, GlState.vid.width, GlState.vid.height); GlState.gl.glMatrixMode(GL11.GL_PROJECTION); GlState.gl.glLoadIdentity(); GlState.gl.glOrthof(0, GlState.vid.width, GlState.vid.height, 0, -99999, 99999); GlState.gl.glMatrixMode(GL11.GL_MODELVIEW); GlState.gl.glLoadIdentity(); GlState.gl.glDisable(GL11.GL_DEPTH_TEST); GlState.gl.glDisable(GL11.GL_CULL_FACE); GlState.gl.glDisable(GL11.GL_BLEND); GlState.gl.glEnable(GL11.GL_ALPHA_TEST); GlState.gl.glColor4f(1, 1, 1, 1); /* * * draw buffer stuff */ if (GlConfig.gl_drawbuffer.modified) { GlConfig.gl_drawbuffer.modified = false; System.out.println("glDrawBuffer commented out here."); // if (GlState.camera_separation == 0 || !GlState.stereo_enabled) { // if (GlConfig.gl_drawbuffer.string.equalsIgnoreCase("GL_FRONT")) // GlState.gl.glDrawBuffer(GL11.GL_FRONT); // else // GlState.gl.glDrawBuffer(GL11.GL_BACK); // } } /* * * texturemode stuff */ if (GlConfig.gl_texturemode.modified) { Images.GL_TextureMode(GlConfig.gl_texturemode.string); GlConfig.gl_texturemode.modified = false; } if (GlConfig.gl_texturealphamode.modified) { Images.GL_TextureAlphaMode(GlConfig.gl_texturealphamode.string); GlConfig.gl_texturealphamode.modified = false; } if (GlConfig.gl_texturesolidmode.modified) { Images.GL_TextureSolidMode(GlConfig.gl_texturesolidmode.string); GlConfig.gl_texturesolidmode.modified = false; } /* * * swapinterval stuff */ Misc.GL_UpdateSwapInterval(); // // clear screen if desired // Entities.R_Clear(); } @Override public KBD getKeyboardHandler() { return new GdxKbdImpl(); } @Override public void GL_ResampleTexture(int[] data, int width, int height, int[] scaled, int scaled_width, int scaled_height) { throw new RuntimeException("NYI resample texture"); } public void checkPendingImages() { for (int i = pendingImages.size() - 1; i >= 0; i--) { Image image = pendingImages.get(i); if (image.ready) { uploadImage(image); pendingImages.remove(i); } } } private Map<String, Pixmap> tmpImages = new HashMap<String, Pixmap>(); private Pixmap getTmpImage(int w, int h) { String name = w + "x" + h; Pixmap image = tmpImages.get(name); if (image == null) { image = new Pixmap(w, h, Pixmap.Format.RGBA8888); tmpImages.put(name, image); } return image; } void texImage2D(Pixmap pixmal, int target, int level, int internalFormat, int format, int type) { GlState.gl.glTexImage2D(target, level, internalFormat, pixmal.getWidth(), pixmal.getHeight(), 0, format, type, pixmal.getPixels()); } void texSubImage2D(Pixmap pixmap, int target, int level, int xOffset, int yOffset, int format, int type) { GlState.gl.glTexSubImage2D(target, level, xOffset, yOffset, pixmap.getWidth(), pixmap.getHeight(), format, type, pixmap.getPixels()); } public void uploadImage(Image image) { GlState.checkError("before upload image"); image.has_alpha = true; image.complete = true; Images.GL_Bind(image.texnum); if (image.type == com.googlecode.gdxquake2.game.common.QuakeImage.it_pic) { GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); texImage2D(image.pixmap, GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE); image.upload_width = image.width; image.upload_height = image.height; } else if (image.type == com.googlecode.gdxquake2.game.common.QuakeImage.it_sky) { GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); if (Images.skyTarget == null) Images.skyTarget = image; Images.GL_Bind(Images.skyTarget.texnum); if (Images.skyTarget.upload_width != 6 * image.width) { texImage2D(new Pixmap(6 * image.width, image.height, Pixmap.Format.RGBA8888), GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE); Images.skyTarget.upload_width = 6 * image.width; } Images.skyTarget.upload_height = image.height; texSubImage2D(image.pixmap, GL20.GL_TEXTURE_2D, 0, image.width * image.skyIndex, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE); } else { GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR_MIPMAP_LINEAR); GlState.gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); int p2size = 1 << ((int) Math.ceil(Math.log(Math.max(image.width, image.height)) / Math.log(2))); image.upload_width = p2size; image.upload_height = p2size; int level = 0; do { Pixmap canvas = getTmpImage(p2size, p2size); canvas.setColor(0x88888888); canvas.fill(); try { canvas.drawPixmap(image.pixmap, 0, 0, image.pixmap.getWidth(), image.pixmap.getHeight(), 0, 0, p2size, p2size); } catch (Exception e) { GdxQuake2.tools.log("Error rendering image " + image.name + "; size: " + p2size + " MSG: " + e); break; } texImage2D(canvas, GL20.GL_TEXTURE_2D, level++, GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE); p2size /= 2; } while (p2size > 0); } GLDebug.checkError(GlState.gl, "uploadImage"); } static int loadId; @Override public Image GL_LoadNewImage(String name, int type) { final Image image = Images.GL_Find_free_image_t(name, type); name = name.toLowerCase(); // int cut = name.lastIndexOf('.'); // String normalizedName = cut == -1 ? name : name.substring(0, cut); Dimension d = GdxQuake2.getImageSize(name); if (d == null) { name = "install/data/baseq2/" + name; } d = GdxQuake2.getImageSize(name); if (d == null) { image.width = 128; image.height = 128; } else { image.width = d.width; image.height = d.height; } final int loadId = GlRenderer.loadId++; image.loadId = loadId; image.pixmap = new Pixmap(image.width, image.height, Pixmap.Format.RGBA8888); pendingImages.add(image); image.ready = false; GdxQuake2.asyncLocalStorage.getFileHandle(name.toLowerCase() + ".png", new Callback<AsyncFileHandle>() { @Override public void onSuccess(AsyncFileHandle result) { AsyncPixmapLoader.loadPixmap(result, new Callback<Pixmap>() { @Override public void onSuccess(Pixmap pixmap) { //Image was recycled in the meantime. if (image.loadId != loadId) { return; } image.pixmap = pixmap; image.ready = true; } @Override public void onFailure(Throwable cause) { cause.printStackTrace(); } }); } @Override public void onFailure(Throwable e) { e.printStackTrace(); } }); /* if (type != com.googlecode.gdxquake2.core.id.common.QuakeImage.it_pic) { GlState.gl.glTexImage2D(TEXTURE_2D, 0, RGBA, HOLODECK_TEXTURE_SIZE, HOLODECK_TEXTURE_SIZE, 0, RGBA, UNSIGNED_BYTE, holoDeckTexture); GlState.gl.glTexParameterf(TEXTURE_2D, TEXTURE_MIN_FILTER, LINEAR); GlState.gl.glTexParameterf(TEXTURE_2D, TEXTURE_MAG_FILTER, LINEAR); }*/ return image; } }