/*
* JaamSim Discrete Event Simulation
* Copyright (C) 2013 Ausenco Engineering Canada Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jaamsim.render;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
import com.jaamsim.MeshFiles.BlockReader;
import com.jaamsim.MeshFiles.MeshData;
import com.jaamsim.MeshFiles.MeshReader;
import com.jaamsim.MeshFiles.ObjReader;
import com.jaamsim.collada.ColParser;
import com.jaamsim.ui.LogBox;
public class MeshDataCache {
private static final HashMap<MeshProtoKey, MeshData> dataMap = new HashMap<>();
private static final HashMap<MeshProtoKey, AtomicBoolean> loadingMap = new HashMap<>();
private static final HashSet<MeshProtoKey> badMeshSet = new HashSet<>();
private static MeshData badMesh = null;
public static final MeshProtoKey BAD_MESH_KEY;
static {
try {
BAD_MESH_KEY = new MeshProtoKey(TexCache.class.getResource("/resources/shapes/bad-mesh.jsm").toURI());
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
// Fetch, or lazily initialize the mesh data
public static MeshData getMeshData(MeshProtoKey key) {
synchronized (dataMap) {
MeshData data = dataMap.get(key);
if (data != null) {
return data;
}
}
synchronized (badMeshSet) {
if (badMeshSet.contains(key)) {
return getBadMesh();
}
}
AtomicBoolean loadingFlag = null;
synchronized (loadingMap) {
loadingFlag = loadingMap.get(key);
}
if (loadingFlag != null) {
// Someone already triggered a delayed load for this mesh, let's just wait for that one...
synchronized (loadingFlag) {
while (!loadingFlag.get()) {
try {
loadingFlag.wait();
} catch (InterruptedException ex) {}
}
}
synchronized (dataMap) {
return dataMap.get(key);
}
}
// Release the lock long enough to load the model
String fileString = key.getURI().toString();
String ext = fileString.substring(fileString.length() - 3, fileString.length());
MeshData data = null;
try {
if (ext.toUpperCase().equals("DAE")) {
data = ColParser.parse(key.getURI());
} else if (ext.toUpperCase().equals("JSM")) {
data = MeshReader.parse(key.getURI());
} else if (ext.toUpperCase().equals("JSB")) {
data = BlockReader.parse(key.getURI());
} else if (ext.toUpperCase().equals("OBJ")) {
data = ObjReader.parse(key.getURI());
} else {
assert(false);
}
} catch (Exception ex) {
LogBox.formatRenderLog("Could not load mesh: %s \n Error: %s\n", key.getURI().toString(), ex.getMessage());
synchronized (badMeshSet) {
badMeshSet.add(key);
return getBadMesh();
}
}
synchronized (dataMap) {
dataMap.put(key, data);
}
return data;
}
public static boolean isMeshLoaded(MeshProtoKey key) {
synchronized (dataMap) {
return dataMap.containsKey(key);
}
}
/**
* Load the mesh in a new thread, then notify on 'notifier'
* @param key
* @param notifier
*/
public static void loadMesh(final MeshProtoKey key) {
final AtomicBoolean notifier = new AtomicBoolean();
synchronized (loadingMap) {
loadingMap.put(key, notifier);
}
new Thread() {
@Override
public void run() {
getMeshData(key); // Cause the lazy initializer to load the mesh (or return quickly if already loaded)
notifier.set(true);
synchronized(notifier) {
notifier.notifyAll();
}
}
}.start();
}
// Lazily load the bad mesh data
public synchronized static MeshData getBadMesh() {
if (badMesh == null) {
badMesh = MeshReader.parse(BAD_MESH_KEY.getURI());
}
return badMesh;
}
}