/** * Writes <code>textureCoordinates</code> in a line vt at OBJ format, * if the texture coordinates wasn't written yet. */ private void writeTextureCoordinates(TexCoord2f textureCoordinates, int index, int[] textureCoordinatesIndexSubstitutes) throws IOException { Integer textureCoordinatesIndex = this.textureCoordinatesIndices.get(textureCoordinates); if (textureCoordinatesIndex == null) { textureCoordinatesIndexSubstitutes[index] = this.textureCoordinatesIndices.size() + 1; this.textureCoordinatesIndices.put(textureCoordinates, textureCoordinatesIndexSubstitutes[index]); // Write only once unique texture coordinates this.out.write("vt " + format(textureCoordinates.x) + " " + format(textureCoordinates.y) + " 0\n"); } else { textureCoordinatesIndexSubstitutes[index] = textureCoordinatesIndex; } }
/** * Returns texture coordinates generated with <code>texCoordGeneration</code> computed * as described in <code>TexCoordGeneration</code> javadoc. */ private TexCoord2f generateTextureCoordinates(float x, float y, float z, Vector4f planeS, Vector4f planeT) { return new TexCoord2f(x * planeS.x + y * planeS.y + z * planeS.z + planeS.w, x * planeT.x + y * planeT.y + z * planeT.z + planeT.w); }
/** * Writes <code>textureCoordinates</code> in a line vt at OBJ format, * if the texture coordinates wasn't written yet. */ private void writeTextureCoordinates(TexCoord2f textureCoordinates, int index, int [] textureCoordinatesIndexSubstitutes) throws IOException { Integer textureCoordinatesIndex = this.textureCoordinatesIndices.get(textureCoordinates); if (textureCoordinatesIndex == null) { textureCoordinatesIndexSubstitutes [index] = this.textureCoordinatesIndices.size() + 1; this.textureCoordinatesIndices.put(textureCoordinates, textureCoordinatesIndexSubstitutes [index]); // Write only once unique texture coordinates this.out.write("vt " + format(textureCoordinates.x) + " " + format(textureCoordinates.y) + " 0\n"); } else { textureCoordinatesIndexSubstitutes [index] = textureCoordinatesIndex; } }
public Mesh3DS(String name, Point3f[] vertices, TexCoord2f[] textureCoordinates, Face3DS[] faces, Short color, Transform3D transform) { this.name = name; this.vertices = vertices; this.textureCoordinates = textureCoordinates; this.faces = faces; this.color = color; this.transform = transform; }
/** * Stores <code>textureCoordinates</code> in <code>uvs</code>. */ private void exportTextureCoordinates(TexCoord2f textureCoordinates, int index, float[] uvs) { index *= 2; uvs[index++] = textureCoordinates.x; uvs[index] = textureCoordinates.y; }
/** * Get the texture coordinates as an array * @return texture coordinates as array */ public TexCoord2f[] getTextureCoordinates() { if (_gridSize <= 1) {return null;} final int numNodes = _gridSize * _gridSize; final float gridStep = 1.0f / (_gridSize - 1); // Build all the required nodes TexCoord2f[] nodes = new TexCoord2f[numNodes]; for (int i=0; i<_gridSize; i++) { for (int j=0; j<_gridSize; j++) { nodes[j * _gridSize + i] = new TexCoord2f(gridStep * i, 1.0f - gridStep * j); } } // Now put these nodes into a new result array (repeating nodes as necessary) final int resultSize = _gridSize * (_gridSize * 2 - 2); TexCoord2f[] result = new TexCoord2f[resultSize]; final int numStrips = _gridSize - 1; int resultIndex = 0; for (int strip=0; strip<numStrips; strip++) { for (int col=0; col<_gridSize; col++) { int bottomNodeIndex = strip * _gridSize + col; int topNodeIndex = bottomNodeIndex + _gridSize; result[resultIndex++] = nodes[bottomNodeIndex]; result[resultIndex++] = nodes[topNodeIndex]; } } return result; }
/** * Writes <code>textureCoordinates</code> in a line vt at OBJ format, if the * texture coordinates wasn't written yet. */ private void writeTextureCoordinates(TexCoord2f textureCoordinates, int index, int[] textureCoordinatesIndexSubstitutes) throws IOException { Integer textureCoordinatesIndex = this.textureCoordinatesIndices.get(textureCoordinates); if (textureCoordinatesIndex == null) { textureCoordinatesIndexSubstitutes[index] = this.textureCoordinatesIndices.size() + 1; this.textureCoordinatesIndices.put(textureCoordinates, textureCoordinatesIndexSubstitutes[index]); // Write only once unique texture coordinates this.out.write("vt " + format(textureCoordinates.x) + " " + format(textureCoordinates.y) + " 0\n"); } else { textureCoordinatesIndexSubstitutes[index] = textureCoordinatesIndex; } }
/** * Adds to ground shape the geometry matching the given area. */ private void addAreaGeometry(Shape3D groundShape, HomeTexture groundTexture, Area area, float elevation) { List<float[][]> areaPoints = getAreaPoints(area, 1, false); if (!areaPoints.isEmpty()) { int vertexCount = 0; int[] stripCounts = new int[areaPoints.size()]; for (int i = 0; i < stripCounts.length; i++) { stripCounts[i] = areaPoints.get(i).length; vertexCount += stripCounts[i]; } Point3f[] geometryCoords = new Point3f[vertexCount]; TexCoord2f[] geometryTextureCoords = groundTexture != null ? new TexCoord2f[vertexCount] : null; float textureWidth; float textureHeight; if (groundTexture != null) { textureWidth = TextureManager.getInstance().getRotatedTextureWidth(groundTexture); textureHeight = TextureManager.getInstance().getRotatedTextureHeight(groundTexture); } else { textureWidth = 0; textureHeight = 0; } int j = 0; for (float[][] areaPartPoints : areaPoints) { for (int i = 0; i < areaPartPoints.length; i++, j++) { float[] point = areaPartPoints[i]; geometryCoords[j] = new Point3f(point[0], elevation, point[1]); if (groundTexture != null) { geometryTextureCoords[j] = new TexCoord2f((point[0] - this.originX) / textureWidth, (this.originY - point[1]) / textureHeight); } } } GeometryInfo geometryInfo = new GeometryInfo(GeometryInfo.POLYGON_ARRAY); geometryInfo.setCoordinates(geometryCoords); if (groundTexture != null) { geometryInfo.setTextureCoordinateParams(1, 2); geometryInfo.setTextureCoordinates(0, geometryTextureCoords); } geometryInfo.setStripCounts(stripCounts); new NormalGenerator(0).generateNormals(geometryInfo); groundShape.addGeometry(geometryInfo.getIndexedGeometryArray()); } }
/** * Adds to ground shape the geometry matching the given area sides. */ private void addAreaSidesGeometry(Shape3D groundShape, HomeTexture groundTexture, float[][] areaPoints, float elevation, float sideHeight) { Point3f[] geometryCoords = new Point3f[areaPoints.length * 4]; TexCoord2f[] geometryTextureCoords = groundTexture != null ? new TexCoord2f[geometryCoords.length] : null; float textureWidth; float textureHeight; if (groundTexture != null) { textureWidth = TextureManager.getInstance().getRotatedTextureWidth(groundTexture); textureHeight = TextureManager.getInstance().getRotatedTextureHeight(groundTexture); } else { textureWidth = 0; textureHeight = 0; } for (int i = 0, j = 0; i < areaPoints.length; i++) { float[] point = areaPoints[i]; float[] nextPoint = areaPoints[i < areaPoints.length - 1 ? i + 1 : 0]; geometryCoords[j++] = new Point3f(point[0], elevation, point[1]); geometryCoords[j++] = new Point3f(point[0], elevation + sideHeight, point[1]); geometryCoords[j++] = new Point3f(nextPoint[0], elevation + sideHeight, nextPoint[1]); geometryCoords[j++] = new Point3f(nextPoint[0], elevation, nextPoint[1]); if (groundTexture != null) { float distance = (float) Point2D.distance(point[0], point[1], nextPoint[0], nextPoint[1]); geometryTextureCoords[j - 4] = new TexCoord2f(point[0] / textureWidth, elevation / textureHeight); geometryTextureCoords[j - 3] = new TexCoord2f(point[0] / textureWidth, (elevation + sideHeight) / textureHeight); geometryTextureCoords[j - 2] = new TexCoord2f((point[0] - distance) / textureWidth, (elevation + sideHeight) / textureHeight); geometryTextureCoords[j - 1] = new TexCoord2f((point[0] - distance) / textureWidth, elevation / textureHeight); } } GeometryInfo geometryInfo = new GeometryInfo(GeometryInfo.QUAD_ARRAY); geometryInfo.setCoordinates(geometryCoords); if (groundTexture != null) { geometryInfo.setTextureCoordinateParams(1, 2); geometryInfo.setTextureCoordinates(0, geometryTextureCoords); } new NormalGenerator(0).generateNormals(geometryInfo); groundShape.addGeometry(geometryInfo.getIndexedGeometryArray()); }
public TexCoord2f[] getTextureCoordinates() { return this.textureCoordinates; }
/** * Returns the scene parsed from a stream. */ private Scene parseObjectStream(Reader reader, URL baseUrl) throws IOException { this.vertices = new ArrayList<Point3f>(); this.textureCoordinates = new ArrayList<TexCoord2f>(); this.normals = new ArrayList<Vector3f>(); this.groups = new LinkedHashMap<String, Group>(); this.currentGroup = new Group("default"); this.groups.put("default", this.currentGroup); this.currentMaterial = "default"; this.appearances = new HashMap<String, Appearance>(DEFAULT_APPEARANCES); StreamTokenizer tokenizer = createTokenizer(reader); while (tokenizer.nextToken() != StreamTokenizer.TT_EOF) { switch (tokenizer.ttype) { case StreamTokenizer.TT_WORD: parseObjectLine(tokenizer, baseUrl); break; case StreamTokenizer.TT_EOL: break; default: throw new IncorrectFormatException( "Unexpected token " + tokenizer.sval + " at row " + tokenizer.lineno()); } } try { return createScene(); } finally { this.vertices = null; this.textureCoordinates = null; this.normals = null; this.groups = null; this.appearances = null; } }
/** * Returns a half sphere oriented inward and with texture ordinates * that spread along an hemisphere. */ private Geometry createHalfSphereGeometry(boolean top) { final int divisionCount = 48; Point3f[] coords = new Point3f[divisionCount * divisionCount]; TexCoord2f[] textureCoords = top ? new TexCoord2f[divisionCount * divisionCount] : null; Color3f[] colors = top ? null : new Color3f[divisionCount * divisionCount]; for (int i = 0, k = 0; i < divisionCount; i++) { double alpha = i * 2 * Math.PI / divisionCount; float cosAlpha = (float) Math.cos(alpha); float sinAlpha = (float) Math.sin(alpha); double nextAlpha = (i + 1) * 2 * Math.PI / divisionCount; float cosNextAlpha = (float) Math.cos(nextAlpha); float sinNextAlpha = (float) Math.sin(nextAlpha); for (int j = 0; j < divisionCount / 4; j++) { double beta = 2 * j * Math.PI / divisionCount; float cosBeta = (float) Math.cos(beta); float sinBeta = (float) Math.sin(beta); // Correct the bottom of the hemisphere to avoid seeing a bottom hemisphere at the horizon float y = j != 0 ? (top ? sinBeta : -sinBeta) : -0.01f; double nextBeta = 2 * (j + 1) * Math.PI / divisionCount; if (!top) { nextBeta = -nextBeta; } float cosNextBeta = (float) Math.cos(nextBeta); float sinNextBeta = (float) Math.sin(nextBeta); if (top) { coords[k] = new Point3f(cosAlpha * cosBeta, y, sinAlpha * cosBeta); textureCoords[k++] = new TexCoord2f((float) i / divisionCount, sinBeta); coords[k] = new Point3f(cosNextAlpha * cosBeta, y, sinNextAlpha * cosBeta); textureCoords[k++] = new TexCoord2f((float) (i + 1) / divisionCount, sinBeta); coords[k] = new Point3f(cosNextAlpha * cosNextBeta, sinNextBeta, sinNextAlpha * cosNextBeta); textureCoords[k++] = new TexCoord2f((float) (i + 1) / divisionCount, sinNextBeta); coords[k] = new Point3f(cosAlpha * cosNextBeta, sinNextBeta, sinAlpha * cosNextBeta); textureCoords[k++] = new TexCoord2f((float) i / divisionCount, sinNextBeta); } else { coords[k] = new Point3f(cosAlpha * cosBeta, y, sinAlpha * cosBeta); float color1 = .9f + y * .5f; colors[k++] = new Color3f(color1, color1, color1); coords[k] = new Point3f(cosAlpha * cosNextBeta, sinNextBeta, sinAlpha * cosNextBeta); float color2 = .9f + sinNextBeta * .5f; colors[k++] = new Color3f(color2, color2, color2); coords[k] = new Point3f(cosNextAlpha * cosNextBeta, sinNextBeta, sinNextAlpha * cosNextBeta); colors[k++] = new Color3f(color2, color2, color2); coords[k] = new Point3f(cosNextAlpha * cosBeta, y, sinNextAlpha * cosBeta); colors[k++] = new Color3f(color1, color1, color1); } } } GeometryInfo geometryInfo = new GeometryInfo(GeometryInfo.QUAD_ARRAY); geometryInfo.setCoordinates(coords); if (textureCoords != null) { geometryInfo.setTextureCoordinateParams(1, 2); geometryInfo.setTextureCoordinates(0, textureCoords); } if (colors != null) { geometryInfo.setColors(colors); } geometryInfo.indexify(); geometryInfo.compact(); Geometry halfSphereGeometry = geometryInfo.getIndexedGeometryArray(); return halfSphereGeometry; }
@Override public void extract() throws Exception { /* * Some models don't work at all (LIFT.CHR and ITEMS.CHR). They seem to * be incomplete/garbage files that were probably included by mistake */ super.extract(); int rootChunkDataSize = super.resourceBytes.length - 2 * DataReader.INT_SIZE; byte[] rootChunkData = new byte[rootChunkDataSize]; System.arraycopy(super.resourceBytes, 2 * DataReader.INT_SIZE, rootChunkData, 0, rootChunkDataSize); AbstractChunk rootChunk = new Chunk0x8000(ROOT_CHUNK_ID, rootChunkData); rootChunk.readContents(); Chunk0x7f01 textureOffsetsChunk = (Chunk0x7f01) rootChunk.getChunksById(TEXTURE_OFFSETS_CHUNK_ID).get(0); List<AbstractChunk> shapeChunks = rootChunk.getChunksById(SHAPE_CHUNK_ID); Chunk0x7f04 textureChunk = (Chunk0x7f04) rootChunk.getChunksById(TEXTURE_CHUNK_ID).get(0); Chunk0x7f05 shapePositionsChunk = (Chunk0x7f05) rootChunk.getChunksById(SHAPE_POSITIONS_CHUNK_ID).get(0); Chunk0x7f06 shapePositionIdsChunk = (Chunk0x7f06) rootChunk.getChunksById(SHAPE_POSITION_IDS_CHUNK_ID).get(0); shapePositionIdsChunk.mapPositions(shapePositionsChunk); List<Point3f> vertexList = new ArrayList<>(); List<Integer> stripCountList = new ArrayList<>(); List<TexCoord2f> texCoordList = new ArrayList<>(); int[] textureOffsets = textureOffsetsChunk.getTextureOffsets(); short[] texturePixelIndices = textureChunk.getTexturePixelIndices(); int textureWidth = textureChunk.getWidth(); int textureHeight = textureChunk.getHeight(); for (AbstractChunk chunk : shapeChunks) { Chunk0x7f02 shape = (Chunk0x7f02) chunk; int shapeId = shape.getShapeId(); Polygon[] polygons = shape.getPolygons(); Point3f[] shapeVertices = shape.getVertices(); for (Polygon polygon : polygons) { int textureOffsetIndex = polygon.getTextureOffsetIndex(); int textureStartPixel = textureOffsets[textureOffsetIndex]; polygon.setPixelSearchStart(textureStartPixel); polygon.setTexturePixelIndices(texturePixelIndices); polygon.setTextureWidth(textureWidth); polygon.decode(); int[] vertexIndices = polygon.getShapeVertexIndices(); // Going backwards, otherwise faces are inside out for (int i = vertexIndices.length - 1; i >= 0; i--) { Point3f vertex = (Point3f) shapeVertices[vertexIndices[i]].clone(); vertex.add(shapePositionIdsChunk.getShapePosition(shapeId)); vertexList.add(vertex); } Point[] relativeUVs = polygon.getRelativeUVs(); for (int i = relativeUVs.length - 1; i >= 0; i--) { int texOriginX = textureStartPixel % textureWidth; int texOriginY = textureStartPixel / textureWidth; float u = (float) (relativeUVs[i].getX() + texOriginX); u /= textureWidth; float v = (float) (relativeUVs[i].getY() + texOriginY); // The UV 0,0 is at the bottom left v = textureHeight - v; v /= textureHeight; texCoordList.add(new TexCoord2f(u, v)); } stripCountList.add(polygon.getVerticeCount()); } } Point3f[] vertices = vertexList.toArray(new Point3f[vertexList.size()]); int[] stripCounts = stripCountList.stream().mapToInt(i -> i).toArray(); TexCoord2f[] texCoords = texCoordList.toArray(new TexCoord2f[texCoordList.size()]); GeometryInfo geometryInfo = new GeometryInfo(GeometryInfo.POLYGON_ARRAY); geometryInfo.setCoordinates(vertices); geometryInfo.setStripCounts(stripCounts); geometryInfo.setTextureCoordinateParams(1, 2); geometryInfo.setTextureCoordinates(0, texCoords); Appearance appearence = new Appearance(); TextureLoader textureLoader = new TextureLoader((BufferedImage) textureChunk.getTexture()); appearence.setTexture(textureLoader.getTexture()); NormalGenerator normalGenerator = new NormalGenerator(); normalGenerator.generateNormals(geometryInfo); Stripifier stripifier = new Stripifier(); stripifier.stripify(geometryInfo); GeometryArray geometryArray = geometryInfo.getGeometryArray(); this.shape3d = new Shape3D(geometryArray); this.shape3d.setAppearance(appearence); }
/** * Returns texture coordinates generated with * <code>texCoordGeneration</code> computed as described in * <code>TexCoordGeneration</code> javadoc. */ private TexCoord2f generateTextureCoordinates(float x, float y, float z, Vector4f planeS, Vector4f planeT) { return new TexCoord2f(x * planeS.x + y * planeS.y + z * planeS.z + planeS.w, x * planeT.x + y * planeT.y + z * planeT.z + planeT.w); }