![JAR search and dependency download from the Maven repository](/logo.png)
darwin.jopenctm.compression.MG2Decoder Maven / Gradle / Ivy
/*
* Copyright (C) 2012 Daniel Heinrich
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* (version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see
* or write to the Free Software Foundation, Inc., 51 Franklin Street,
* Fifth Floor, Boston, MA 02110-1301 USA.
*/
package darwin.jopenctm.compression;
import darwin.annotations.ServiceProvider;
import darwin.jopenctm.data.*;
import darwin.jopenctm.errorhandling.BadFormatException;
import darwin.jopenctm.errorhandling.InvalidDataException;
import darwin.jopenctm.io.*;
import java.io.IOException;
import static darwin.jopenctm.compression.CommonAlgorithms.*;
import static darwin.jopenctm.data.Mesh.*;
import static java.lang.Math.*;
/**
*
* @author daniel
*/
@ServiceProvider(MeshDecoder.class)
public class MG2Decoder extends MG1Decoder {
public static final int MG2_Tag = CtmFileReader.getTagInt("MG2\0");
public static final int MG2_HEADER_TAG = CtmFileReader.getTagInt("MG2H");
public static final int GIDX = CtmFileReader.getTagInt("GIDX");
@Override
public boolean isFormatSupported(int tag, int version) {
return tag == MG2_Tag && version == RawDecoder.FORMAT_VERSION;
}
@Override
public Mesh decode(MeshInfo minfo, CtmInputStream in) throws IOException, BadFormatException, InvalidDataException {
int vc = minfo.getVertexCount();
checkTag(in.readLittleInt(), MG2_HEADER_TAG);
float vertexPrecision = in.readLittleFloat();
float normalPrecision = in.readLittleFloat();
Grid grid = Grid.fromStream(in);
if(!grid.checkIntegrity()) {
throw new InvalidDataException("The vertex size grid is corrupt!");
}
float[] vertices = readVertices(in, grid, vc, vertexPrecision);
int[] indices = readIndices(in, minfo.getTriangleCount(), vc);
float[] normals = null;
if (minfo.hasNormals()) {
normals = readNormals(in, vertices, indices, normalPrecision, vc);
}
AttributeData[] uvData = new AttributeData[minfo.getUvMapCount()];
for (int i = 0; i < uvData.length; i++) {
uvData[i] = readUvData(in, vc);
}
AttributeData[] attributs = new AttributeData[minfo.getAttrCount()];
for (int i = 0; i < attributs.length; i++) {
attributs[i] = readAttribute(in, vc);
}
return new Mesh(vertices, normals, indices, uvData, attributs);
}
private float[] readVertices(CtmInputStream in, Grid grid, int vcount, float precision) throws IOException, BadFormatException {
checkTag(in.readLittleInt(), VERT);
int[] intVertices = in.readPackedInts(vcount, CTM_POSITION_ELEMENT_COUNT, false);
checkTag(in.readLittleInt(), GIDX);
int[] gridIndices = in.readPackedInts(vcount, 1, false);
for (int i = 1; i < vcount; i++) {
gridIndices[i] += gridIndices[i - 1];
}
return restoreVertices(intVertices, gridIndices, grid, precision);
}
private int[] readIndices(CtmInputStream in, int triCount, int vcount) throws IOException, InvalidDataException, BadFormatException {
checkTag(in.readLittleInt(), INDX);
int[] indices = in.readPackedInts(triCount, 3, false);
restoreIndices(triCount, indices);
for (int i : indices) {
if (i > vcount) {
throw new InvalidDataException("One element of the indice array "
+ "points to a none existing vertex(id: " + i + ")");
}
}
return indices;
}
private float[] readNormals(CtmInputStream in, float[] vertices, int[] indices,
float normalPrecision, int vcount) throws IOException, BadFormatException {
checkTag(in.readLittleInt(), NORM);
int[] intNormals = in.readPackedInts(vcount, CTM_NORMAL_ELEMENT_COUNT, false);
return restoreNormals(intNormals, vertices, indices, normalPrecision);
}
private AttributeData readUvData(CtmInputStream in, int vcount) throws IOException, BadFormatException, InvalidDataException {
checkTag(in.readLittleInt(), TEXC);
String name = in.readString();
String material = in.readString();
float precision = in.readLittleFloat();
if (precision <= 0f) {
throw new InvalidDataException("A uv precision value <= 0.0 was read");
}
int[] intCoords = in.readPackedInts(vcount, CTM_UV_ELEMENT_COUNT, true);
float[] data = restoreUVCoords(precision, intCoords);
return new AttributeData(name, material, precision, data);
}
private AttributeData readAttribute(CtmInputStream in, int vc) throws IOException, BadFormatException, InvalidDataException {
checkTag(in.readLittleInt(), ATTR);
String name = in.readString();
float precision = in.readLittleFloat();
if (precision <= 0f) {
throw new InvalidDataException("An attribute precision value <= 0.0 was read");
}
int[] intData = in.readPackedInts(vc, CTM_ATTR_ELEMENT_COUNT, true);
float[] data = restoreAttribs(precision, intData);
return new AttributeData(name, null, precision, data);
}
/**
* Calculate inverse derivatives of the vertex attributes.
*/
private float[] restoreAttribs(float precision, int[] intAttribs) {
int ae = CTM_ATTR_ELEMENT_COUNT;
int vc = intAttribs.length / ae;
float[] values = new float[intAttribs.length];
int[] prev = new int[ae];
for (int i = 0; i < vc; ++i) {
// Calculate inverse delta, and convert to floating point
for (int j = 0; j < ae; ++j) {
int value = intAttribs[i * ae + j] + prev[j];
values[i * ae + j] = value * precision;
prev[j] = value;
}
}
return values;
}
/**
* Calculate inverse derivatives of the UV coordinates.
*/
private float[] restoreUVCoords(float precision, int[] intUVCoords) {
int vc = intUVCoords.length / CTM_UV_ELEMENT_COUNT;
float[] values = new float[intUVCoords.length];
int prevU = 0, prevV = 0;
for (int i = 0; i < vc; ++i) {
// Calculate inverse delta
int u = intUVCoords[i * CTM_UV_ELEMENT_COUNT] + prevU;
int v = intUVCoords[i * CTM_UV_ELEMENT_COUNT + 1] + prevV;
// Convert to floating point
values[i * CTM_UV_ELEMENT_COUNT] = u * precision;
values[i * CTM_UV_ELEMENT_COUNT + 1] = v * precision;
prevU = u;
prevV = v;
}
return values;
}
/**
* Convert the normals back to cartesian coordinates.
*/
private float[] restoreNormals(int[] intNormals, float[] vertices, int[] indices, float normalPrecision) {
// Calculate smooth normals (nominal normals)
float[] smoothNormals = calcSmoothNormals(vertices, indices);
float[] normals = new float[vertices.length];
int vc = vertices.length / CTM_POSITION_ELEMENT_COUNT;
int ne = CTM_NORMAL_ELEMENT_COUNT;
for (int i = 0; i < vc; ++i) {
// Get the normal magnitude from the first of the three normal elements
float magn = intNormals[i * ne] * normalPrecision;
// Get phi and theta (spherical coordinates, relative to the smooth normal).
double thetaScale, theta;
int intPhi = intNormals[i * ne + 1];
double phi = intPhi * (0.5 * PI) * normalPrecision;
if (intPhi == 0) {
thetaScale = 0.0f;
} else if (intPhi <= 4) {
thetaScale = PI / 2.0f;
} else {
thetaScale = (2.0f * PI) / intPhi;
}
theta = intNormals[i * ne + 2] * thetaScale - PI;
// Convert the normal from the angular representation (phi, theta) back to
// cartesian coordinates
double[] n2 = new double[3];
n2[0] = sin(phi) * cos(theta);
n2[1] = sin(phi) * sin(theta);
n2[2] = cos(phi);
float[] basisAxes = makeNormalCoordSys(smoothNormals, i * ne);
double[] n = new double[3];
for (int j = 0; j < 3; ++j) {
n[j] = basisAxes[j] * n2[0]
+ basisAxes[3 + j] * n2[1]
+ basisAxes[6 + j] * n2[2];
}
// Apply normal magnitude, and output to the normals array
for (int j = 0; j < 3; ++j) {
normals[i * ne + j] = (float) (n[j] * magn);
}
}
return normals;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy