/** * Updates a subregion of the content area of this texture using the given data. If automatic * mipmap generation is in use (see {@link #isUsingAutoMipmapGeneration * isUsingAutoMipmapGeneration}), updates to the base (level 0) mipmap will cause the lower-level * mipmaps to be regenerated, and updates to other mipmap levels will be ignored. Otherwise, if * automatic mipmap generation is not in use, only updates the specified mipmap level and does not * re-generate mipmaps if they were originally produced or loaded. * * @param data the image data to be uploaded to this texture * @param mipmapLevel the mipmap level of the texture to set. If this is non-zero and the * TextureData contains mipmap data, the appropriate mipmap level will be selected. * @param x the x offset (in pixels) relative to the lower-left corner of this texture * @param y the y offset (in pixels) relative to the lower-left corner of this texture * @throws GLException if no OpenGL context was current or if any OpenGL-related errors occurred */ public void updateSubImage(TextureData data, int mipmapLevel, int x, int y) throws GLException { if (usingAutoMipmapGeneration && mipmapLevel != 0) { // When we're using mipmap generation via GL_GENERATE_MIPMAP, we // don't need to update other mipmap levels return; } bind(); updateSubImageImpl(data, target, mipmapLevel, x, y, 0, 0, data.getWidth(), data.getHeight()); }
@Override public void apply(AssetDataFile input, TextureData assetData) throws IOException { try (InputStreamReader reader = new InputStreamReader(input.openStream(), Charsets.UTF_8)) { TextureMetadata metadata = gson.fromJson(reader, TextureMetadata.class); if (metadata.filterMode != null) { assetData.setFilterMode(metadata.filterMode); } if (metadata.wrapMode != null) { assetData.setWrapMode(metadata.wrapMode); } if (metadata.type != null) { assetData.setType(metadata.type); } } }
public TextureReference getTextureFromResource(GL10 gl, int resourceID) { // If the texture already exists, return it. TextureData texData = mResourceIdToTextureMap.get(resourceID); if (texData != null) { // Increment the reference count texData.refCount++; return texData.ref; } TextureReferenceImpl tex = createTextureFromResource(gl, resourceID); // Add it to the map. TextureData data = new TextureData(); data.ref = tex; data.refCount = 1; mResourceIdToTextureMap.put(resourceID, data); return tex; }
private void checkCompressedTextureExtensions(TextureData data) { GL gl = GLU.getCurrentGL(); if (data.isDataCompressed()) { switch (data.getInternalFormat()) { case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL.GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case GL.GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: case GL.GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: if (!gl.isExtensionAvailable("GL_EXT_texture_compression_s3tc") && !gl.isExtensionAvailable("GL_NV_texture_compression_vtc")) { throw new GLException("DXTn compressed textures not supported by this graphics card"); } break; default: // FIXME: should test availability of more texture // compression extensions here break; } } }
/** * Updates a subregion of the content area of this texture using the specified sub-region of the * given data. If automatic mipmap generation is in use (see {@link #isUsingAutoMipmapGeneration * isUsingAutoMipmapGeneration}), updates to the base (level 0) mipmap will cause the lower-level * mipmaps to be regenerated, and updates to other mipmap levels will be ignored. Otherwise, if * automatic mipmap generation is not in use, only updates the specified mipmap level and does not * re-generate mipmaps if they were originally produced or loaded. This method is only supported * for uncompressed TextureData sources. * * @param data the image data to be uploaded to this texture * @param mipmapLevel the mipmap level of the texture to set. If this is non-zero and the * TextureData contains mipmap data, the appropriate mipmap level will be selected. * @param dstx the x offset (in pixels) relative to the lower-left corner of this texture where * the update will be applied * @param dsty the y offset (in pixels) relative to the lower-left corner of this texture where * the update will be applied * @param srcx the x offset (in pixels) relative to the lower-left corner of the supplied * TextureData from which to fetch the update rectangle * @param srcy the y offset (in pixels) relative to the lower-left corner of the supplied * TextureData from which to fetch the update rectangle * @param width the width (in pixels) of the rectangle to be updated * @param height the height (in pixels) of the rectangle to be updated * @throws GLException if no OpenGL context was current or if any OpenGL-related errors occurred */ public void updateSubImage( TextureData data, int mipmapLevel, int dstx, int dsty, int srcx, int srcy, int width, int height) throws GLException { if (data.isDataCompressed()) { throw new GLException( "updateSubImage specifying a sub-rectangle is not supported for compressed TextureData"); } if (usingAutoMipmapGeneration && mipmapLevel != 0) { // When we're using mipmap generation via GL_GENERATE_MIPMAP, we // don't need to update other mipmap levels return; } bind(); updateSubImageImpl(data, target, mipmapLevel, dstx, dsty, srcx, srcy, width, height); }
private void updateSubImageImpl( TextureData data, int newTarget, int mipmapLevel, int dstx, int dsty, int srcx, int srcy, int width, int height) throws GLException { GL gl = GLU.getCurrentGL(); data.setHaveEXTABGR(gl.isExtensionAvailable("GL_EXT_abgr")); data.setHaveGL12(gl.isExtensionAvailable("GL_VERSION_1_2")); Buffer buffer = data.getBuffer(); if (buffer == null && data.getMipmapData() == null) { // Assume user just wanted to get the Texture object allocated return; } int rowlen = data.getRowLength(); int dataWidth = data.getWidth(); int dataHeight = data.getHeight(); if (data.getMipmapData() != null) { // Compute the width, height and row length at the specified mipmap level // Note we do not support specification of the row length for // mipmapped textures at this point for (int i = 0; i < mipmapLevel; i++) { width = Math.max(width / 2, 1); height = Math.max(height / 2, 1); dataWidth = Math.max(dataWidth / 2, 1); dataHeight = Math.max(dataHeight / 2, 1); } rowlen = 0; buffer = data.getMipmapData()[mipmapLevel]; } // Clip incoming rectangles to what is available both on this // texture and in the incoming TextureData if (srcx < 0) { width += srcx; srcx = 0; } if (srcy < 0) { height += srcy; srcy = 0; } // NOTE: not sure whether the following two are the correct thing to do if (dstx < 0) { width += dstx; dstx = 0; } if (dsty < 0) { height += dsty; dsty = 0; } if (srcx + width > dataWidth) { width = dataWidth - srcx; } if (srcy + height > dataHeight) { height = dataHeight - srcy; } if (dstx + width > texWidth) { width = texWidth - dstx; } if (dsty + height > texHeight) { height = texHeight - dsty; } checkCompressedTextureExtensions(data); if (data.isDataCompressed()) { gl.glCompressedTexSubImage2D( newTarget, mipmapLevel, dstx, dsty, width, height, data.getInternalFormat(), buffer.remaining(), buffer); } else { int[] align = new int[1]; int[] rowLength = new int[1]; int[] skipRows = new int[1]; int[] skipPixels = new int[1]; gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment gl.glGetIntegerv(GL.GL_UNPACK_ROW_LENGTH, rowLength, 0); // save row length gl.glGetIntegerv(GL.GL_UNPACK_SKIP_ROWS, skipRows, 0); // save skipped rows gl.glGetIntegerv(GL.GL_UNPACK_SKIP_PIXELS, skipPixels, 0); // save skipped pixels gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment()); if (DEBUG && VERBOSE) { System.out.println("Row length = " + rowlen); System.out.println("skip pixels = " + srcx); System.out.println("skip rows = " + srcy); System.out.println("dstx = " + dstx); System.out.println("dsty = " + dsty); System.out.println("width = " + width); System.out.println("height = " + height); } gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, rowlen); gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, srcy); gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, srcx); gl.glTexSubImage2D( newTarget, mipmapLevel, dstx, dsty, width, height, data.getPixelFormat(), data.getPixelType(), buffer); gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment gl.glPixelStorei(GL.GL_UNPACK_ROW_LENGTH, rowLength[0]); // restore row length gl.glPixelStorei(GL.GL_UNPACK_SKIP_ROWS, skipRows[0]); // restore skipped rows gl.glPixelStorei(GL.GL_UNPACK_SKIP_PIXELS, skipPixels[0]); // restore skipped pixels } }
/** * Updates the content area of the specified target of this texture using the data in the given * image. In general this is intended for construction of cube maps. * * @throws GLException if no OpenGL context was current or if any OpenGL-related errors occurred */ public void updateImage(TextureData data, int target) throws GLException { GL gl = GLU.getCurrentGL(); imgWidth = data.getWidth(); imgHeight = data.getHeight(); aspectRatio = (float) imgWidth / (float) imgHeight; mustFlipVertically = data.getMustFlipVertically(); int texTarget = 0; int texParamTarget = this.target; // See whether we have automatic mipmap generation support boolean haveAutoMipmapGeneration = (gl.isExtensionAvailable("GL_VERSION_1_4") || gl.isExtensionAvailable("GL_SGIS_generate_mipmap")); // Indicate to the TextureData what functionality is available data.setHaveEXTABGR(gl.isExtensionAvailable("GL_EXT_abgr")); data.setHaveGL12(gl.isExtensionAvailable("GL_VERSION_1_2")); // Note that automatic mipmap generation doesn't work for // GL_ARB_texture_rectangle if ((!isPowerOfTwo(imgWidth) || !isPowerOfTwo(imgHeight)) && !haveNPOT(gl)) { haveAutoMipmapGeneration = false; } boolean expandingCompressedTexture = false; if (data.getMipmap() && !haveAutoMipmapGeneration) { // GLU always scales the texture's dimensions to be powers of // two. It also doesn't really matter exactly what the texture // width and height are because the texture coords are always // between 0.0 and 1.0. imgWidth = nextPowerOfTwo(imgWidth); imgHeight = nextPowerOfTwo(imgHeight); texWidth = imgWidth; texHeight = imgHeight; texTarget = GL.GL_TEXTURE_2D; } else if ((isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) || haveNPOT(gl)) { if (DEBUG) { if (isPowerOfTwo(imgWidth) && isPowerOfTwo(imgHeight)) { System.err.println("Power-of-two texture"); } else { System.err.println("Using GL_ARB_texture_non_power_of_two"); } } texWidth = imgWidth; texHeight = imgHeight; texTarget = GL.GL_TEXTURE_2D; } else if (haveTexRect(gl) && !data.isDataCompressed()) { // GL_ARB_texture_rectangle does not work for compressed textures if (DEBUG) { System.err.println("Using GL_ARB_texture_rectangle"); } texWidth = imgWidth; texHeight = imgHeight; texTarget = GL.GL_TEXTURE_RECTANGLE_ARB; } else { // If we receive non-power-of-two compressed texture data and // don't have true hardware support for compressed textures, we // can fake this support by producing an empty "compressed" // texture image, using glCompressedTexImage2D with that to // allocate the texture, and glCompressedTexSubImage2D with the // incoming data. if (data.isDataCompressed()) { if (data.getMipmapData() != null) { // We don't currently support expanding of compressed, // mipmapped non-power-of-two textures to the nearest power // of two; the obvious port of the non-mipmapped code didn't // work throw new GLException( "Mipmapped non-power-of-two compressed textures only supported on OpenGL 2.0 hardware (GL_ARB_texture_non_power_of_two)"); } expandingCompressedTexture = true; } if (DEBUG) { System.err.println("Expanding texture to power-of-two dimensions"); } if (data.getBorder() != 0) { throw new RuntimeException( "Scaling up a non-power-of-two texture which has a border won't work"); } texWidth = nextPowerOfTwo(imgWidth); texHeight = nextPowerOfTwo(imgHeight); texTarget = GL.GL_TEXTURE_2D; } texParamTarget = texTarget; setImageSize(imgWidth, imgHeight, texTarget); if (target != 0) { // Allow user to override auto detection and skip bind step (for // cubemap construction) texTarget = target; if (this.target == 0) { throw new GLException("Override of target failed; no target specified yet"); } texParamTarget = this.target; gl.glBindTexture(texParamTarget, texID); } else { gl.glBindTexture(texTarget, texID); } if (data.getMipmap() && !haveAutoMipmapGeneration) { int[] align = new int[1]; gl.glGetIntegerv(GL.GL_UNPACK_ALIGNMENT, align, 0); // save alignment gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, data.getAlignment()); if (data.isDataCompressed()) { throw new GLException("May not request mipmap generation for compressed textures"); } try { GLU glu = new GLU(); glu.gluBuild2DMipmaps( texTarget, data.getInternalFormat(), data.getWidth(), data.getHeight(), data.getPixelFormat(), data.getPixelType(), data.getBuffer()); } finally { gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment } } else { checkCompressedTextureExtensions(data); Buffer[] mipmapData = data.getMipmapData(); if (mipmapData != null) { int width = texWidth; int height = texHeight; for (int i = 0; i < mipmapData.length; i++) { if (data.isDataCompressed()) { // Need to use glCompressedTexImage2D directly to allocate and fill this image // Avoid spurious memory allocation when possible gl.glCompressedTexImage2D( texTarget, i, data.getInternalFormat(), width, height, data.getBorder(), mipmapData[i].remaining(), mipmapData[i]); } else { // Allocate texture image at this level gl.glTexImage2D( texTarget, i, data.getInternalFormat(), width, height, data.getBorder(), data.getPixelFormat(), data.getPixelType(), null); updateSubImageImpl(data, texTarget, i, 0, 0, 0, 0, data.getWidth(), data.getHeight()); } width = Math.max(width / 2, 1); height = Math.max(height / 2, 1); } } else { if (data.isDataCompressed()) { if (!expandingCompressedTexture) { // Need to use glCompressedTexImage2D directly to allocate and fill this image // Avoid spurious memory allocation when possible gl.glCompressedTexImage2D( texTarget, 0, data.getInternalFormat(), texWidth, texHeight, data.getBorder(), data.getBuffer().capacity(), data.getBuffer()); } else { ByteBuffer buf = DDSImage.allocateBlankBuffer(texWidth, texHeight, data.getInternalFormat()); gl.glCompressedTexImage2D( texTarget, 0, data.getInternalFormat(), texWidth, texHeight, data.getBorder(), buf.capacity(), buf); updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight()); } } else { if (data.getMipmap() && haveAutoMipmapGeneration) { // For now, only use hardware mipmapping for uncompressed 2D // textures where the user hasn't explicitly specified // mipmap data; don't know about interactions between // GL_GENERATE_MIPMAP and glCompressedTexImage2D gl.glTexParameteri(texParamTarget, GL.GL_GENERATE_MIPMAP, GL.GL_TRUE); usingAutoMipmapGeneration = true; } gl.glTexImage2D( texTarget, 0, data.getInternalFormat(), texWidth, texHeight, data.getBorder(), data.getPixelFormat(), data.getPixelType(), null); updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight()); } } } int minFilter = (data.getMipmap() ? GL.GL_LINEAR_MIPMAP_LINEAR : GL.GL_LINEAR); int magFilter = GL.GL_LINEAR; int wrapMode = (gl.isExtensionAvailable("GL_VERSION_1_2") ? GL.GL_CLAMP_TO_EDGE : GL.GL_CLAMP); // REMIND: figure out what to do for GL_TEXTURE_RECTANGLE_ARB if (texTarget != GL.GL_TEXTURE_RECTANGLE_ARB) { gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MIN_FILTER, minFilter); gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_MAG_FILTER, magFilter); gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_S, wrapMode); gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_T, wrapMode); if (this.target == GL.GL_TEXTURE_CUBE_MAP) { gl.glTexParameteri(texParamTarget, GL.GL_TEXTURE_WRAP_R, wrapMode); } } // Don't overwrite target if we're loading e.g. faces of a cube // map if ((this.target == 0) || (this.target == GL.GL_TEXTURE_2D) || (this.target == GL.GL_TEXTURE_RECTANGLE_ARB)) { this.target = texTarget; } // This estimate will be wrong for cube maps estimatedMemorySize = data.getEstimatedMemorySize(); }
@Override public void buildWorldObject() { // FIXME object is not in local coordinates! setPoint(new Point3d()); List<Point2d> pointList = new ArrayList<Point2d>(); for (int i = 0; i < way.getNodesCount(); i++) { Node node = way.getNode(i); pointList.add(perspective.calcPoint(node)); } list = pointList; roadWidth = (float) DEFAULT_ROAD_WIDTH; roadWidth = getRoadWidth(); TextureData texture = getTexture(); Material m = MaterialFactory.createTextureMaterial(texture.getFile()); ModelFactory modelBuilder = ModelFactory.modelBuilder(); int mi = modelBuilder.addMaterial(m); MeshFactory meshWalls = modelBuilder.addMesh("road"); meshWalls.materialID = mi; meshWalls.hasTexture = true; if (list.size() > 1) { FaceFactory leftBorder = meshWalls.addFace(FaceType.QUAD_STRIP); FaceFactory leftPart = meshWalls.addFace(FaceType.QUAD_STRIP); FaceFactory rightBorder = meshWalls.addFace(FaceType.QUAD_STRIP); FaceFactory rightPart = meshWalls.addFace(FaceType.QUAD_STRIP); Vector3d flatSurface = new Vector3d(0, 1, 0); int flatNormalI = meshWalls.addNormal(flatSurface); Point2d beginPoint = list.get(0); for (int i = 1; i < list.size(); i++) { Point2d endPoint = list.get(i); double x = endPoint.x - beginPoint.x; double y = endPoint.y - beginPoint.y; // calc lenght of road segment double mod = Math.sqrt(x * x + y * y); double distance = beginPoint.distance(endPoint); // calc orthogonal for road segment double orthX = x * cos90 + y * sin90; double orthY = -x * sin90 + y * cos90; // calc vector for road width; double normX = roadWidth / 2 * orthX / mod; double normY = roadWidth / 2 * orthY / mod; // calc vector for border width; double borderX = normX + 0.2 * orthX / mod; double borderY = normY + 0.2 * orthY / mod; double uEnd = distance / texture.getLenght(); // left border int tcb1 = meshWalls.addTextCoord(new TextCoord(0, 0.99999d)); // left part of road int tcb2 = meshWalls.addTextCoord(new TextCoord(0, 1 - 0.10d)); // Middle part of road int tcb3 = meshWalls.addTextCoord(new TextCoord(0, 0.00001d)); // right part of road int tcb4 = meshWalls.addTextCoord(new TextCoord(0, 1 - 0.10d)); // right border int tcb5 = meshWalls.addTextCoord(new TextCoord(0, 0.99999d)); // left border int tce1 = meshWalls.addTextCoord(new TextCoord(uEnd, 0.99999d)); // left part of road int tce2 = meshWalls.addTextCoord(new TextCoord(uEnd, 1 - 0.10d)); // Middle part of road int tce3 = meshWalls.addTextCoord(new TextCoord(uEnd, 0.00001d)); // right part of road int tce4 = meshWalls.addTextCoord(new TextCoord(uEnd, 1 - 0.10d)); // right border int tce5 = meshWalls.addTextCoord(new TextCoord(uEnd, 0.99999d)); // left border int wbi1 = meshWalls.addVertex( new Point3d(beginPoint.x + borderX, 0.0d, -(beginPoint.y + borderY))); // left part of road int wbi2 = meshWalls.addVertex(new Point3d(beginPoint.x + normX, 0.1d, -(beginPoint.y + normY))); // middle part of road int wbi3 = meshWalls.addVertex(new Point3d(beginPoint.x, 0.15d, -beginPoint.y)); // right part of road int wbi4 = meshWalls.addVertex(new Point3d(beginPoint.x - normX, 0.1d, -(beginPoint.y - normY))); // right border int wbi5 = meshWalls.addVertex( new Point3d(beginPoint.x - borderX, 0.0d, -(beginPoint.y - borderY))); // left border int wei1 = meshWalls.addVertex(new Point3d(endPoint.x + borderX, 0.0d, -(endPoint.y + borderY))); // left part of road int wei2 = meshWalls.addVertex(new Point3d(endPoint.x + normX, 0.1d, -(endPoint.y + normY))); // middle part of road int wei3 = meshWalls.addVertex(new Point3d(endPoint.x, 0.15d, -endPoint.y)); // right part of road int wei4 = meshWalls.addVertex(new Point3d(endPoint.x - normX, 0.1d, -(endPoint.y - normY))); // right border int wei5 = meshWalls.addVertex(new Point3d(endPoint.x - borderX, 0.0d, -(endPoint.y - borderY))); leftBorder.addVert(wbi1, tcb1, flatNormalI); leftBorder.addVert(wbi2, tcb2, flatNormalI); leftBorder.addVert(wei1, tce1, flatNormalI); leftBorder.addVert(wei2, tce2, flatNormalI); leftPart.addVert(wbi2, tcb2, flatNormalI); leftPart.addVert(wbi3, tcb3, flatNormalI); leftPart.addVert(wei2, tce2, flatNormalI); leftPart.addVert(wei3, tce3, flatNormalI); rightBorder.addVert(wbi3, tcb3, flatNormalI); rightBorder.addVert(wbi4, tcb4, flatNormalI); rightBorder.addVert(wei3, tce3, flatNormalI); rightBorder.addVert(wei4, tce4, flatNormalI); rightPart.addVert(wbi4, tcb4, flatNormalI); rightPart.addVert(wbi5, tcb5, flatNormalI); rightPart.addVert(wei4, tce4, flatNormalI); rightPart.addVert(wei5, tce5, flatNormalI); beginPoint = endPoint; } } model = modelBuilder.toModel(); model.setUseLight(true); model.setUseTexture(true); buildModel = true; }
/** * Specifies texture data for the tile. If texture data is non-null, a new texture is created from * the texture data when the tile is next bound. * * <p>When a texture is created from the texture data, the texture data field is set to null to * indicate that the data has been converted to a texture and its resources may be released. * * @param textureData the texture data, which may be null. */ protected void setTextureData(TextureData textureData) { this.textureData = textureData; if (textureData != null && textureData.getMipmapData() != null) this.hasMipmapData = true; }