mirror of
https://github.com/DarkflameUniverse/NexusDashboard.git
synced 2024-11-25 06:57:19 +00:00
Merge pull request #12 from DarkflameUniverse/property-viewer-v2
Property viewer v2
This commit is contained in:
commit
87384c1b98
@ -12,7 +12,7 @@ from flask_wtf.csrf import CSRFProtect
|
|||||||
from flask_apscheduler import APScheduler
|
from flask_apscheduler import APScheduler
|
||||||
from app.luclient import query_cdclient, register_luclient_jinja_helpers
|
from app.luclient import query_cdclient, register_luclient_jinja_helpers
|
||||||
|
|
||||||
from app.commands import init_db, init_accounts, load_property
|
from app.commands import init_db, init_accounts, load_property, gen_image_cache, gen_model_cache
|
||||||
from app.models import Account, AccountInvitation
|
from app.models import Account, AccountInvitation
|
||||||
|
|
||||||
# Instantiate Flask extensions
|
# Instantiate Flask extensions
|
||||||
@ -65,6 +65,8 @@ def create_app():
|
|||||||
app.cli.add_command(init_db)
|
app.cli.add_command(init_db)
|
||||||
app.cli.add_command(init_accounts)
|
app.cli.add_command(init_accounts)
|
||||||
app.cli.add_command(load_property)
|
app.cli.add_command(load_property)
|
||||||
|
app.cli.add_command(gen_image_cache)
|
||||||
|
app.cli.add_command(gen_model_cache)
|
||||||
|
|
||||||
register_settings(app)
|
register_settings(app)
|
||||||
register_extensions(app)
|
register_extensions(app)
|
||||||
|
@ -7,6 +7,12 @@ from app import db
|
|||||||
from app.models import Account, PlayKey, CharacterInfo, Property, PropertyContent, UGC
|
from app.models import Account, PlayKey, CharacterInfo, Property, PropertyContent, UGC
|
||||||
import pathlib
|
import pathlib
|
||||||
import zlib
|
import zlib
|
||||||
|
import os
|
||||||
|
from wand import image
|
||||||
|
from wand.exceptions import BlobError as BE
|
||||||
|
import app.pylddlib as ldd
|
||||||
|
from multiprocessing import Pool
|
||||||
|
from functools import partial
|
||||||
|
|
||||||
@click.command("init_db")
|
@click.command("init_db")
|
||||||
@click.argument('drop_tables', nargs=1)
|
@click.argument('drop_tables', nargs=1)
|
||||||
@ -89,6 +95,54 @@ def load_property(zone, player):
|
|||||||
)
|
)
|
||||||
new_prop_content.save()
|
new_prop_content.save()
|
||||||
|
|
||||||
|
@click.command("gen_image_cache")
|
||||||
|
def gen_image_cache():
|
||||||
|
luclient = pathlib.Path('app/luclient/res')
|
||||||
|
files = [path for path in luclient.rglob("*.dds") if path.is_file()]
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
cache = get_cache_file(file).with_suffix(".png")
|
||||||
|
if not cache.exists():
|
||||||
|
try:
|
||||||
|
print(f"Convert {file.as_posix()} to {cache}")
|
||||||
|
cache.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with image.Image(filename=str(file.as_posix())) as img:
|
||||||
|
img.compression = "no"
|
||||||
|
img.save(filename=str(cache.as_posix()))
|
||||||
|
except BE:
|
||||||
|
return print(f"Error on {file}")
|
||||||
|
|
||||||
|
@click.command("gen_model_cache")
|
||||||
|
def gen_model_cache():
|
||||||
|
luclient = pathlib.Path('app/luclient/res')
|
||||||
|
files = [path for path in luclient.rglob("*.lxfml") if path.is_file()]
|
||||||
|
pool = Pool(processes=4)
|
||||||
|
pool.map(partial(convert_lxfml_to_obj, lod=0), files)
|
||||||
|
pool.map(partial(convert_lxfml_to_obj, lod=1), files)
|
||||||
|
pool.map(partial(convert_lxfml_to_obj, lod=2), files)
|
||||||
|
|
||||||
|
def convert_lxfml_to_obj(file, lod):
|
||||||
|
mtl = get_cache_file(file).with_suffix(f".lod{lod}.mtl")
|
||||||
|
if not mtl.exists():
|
||||||
|
mtl.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
print(f"Convert LXFML {file.as_posix()} to obj and mtl @ {mtl}")
|
||||||
|
try:
|
||||||
|
ldd.main(str(file.as_posix()), str(mtl.with_suffix("").as_posix()), lod) # convert to OBJ
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR on {file}:\n {e}")
|
||||||
|
else:
|
||||||
|
# print(f"Already Exists: {file} with LOD {lod}")
|
||||||
|
return
|
||||||
|
|
||||||
|
def get_cache_file(path):
|
||||||
|
# convert to list so that we can change elements
|
||||||
|
parts = list(path.parts)
|
||||||
|
|
||||||
|
# replace part that matches src with dst
|
||||||
|
parts[parts.index("luclient")] = "cache"
|
||||||
|
del parts[parts.index("res")]
|
||||||
|
|
||||||
|
return pathlib.Path(*parts)
|
||||||
|
|
||||||
def find_or_create_account(name, email, password, gm_level=9):
|
def find_or_create_account(name, email, password, gm_level=9):
|
||||||
""" Find existing account or create new account """
|
""" Find existing account or create new account """
|
||||||
@ -119,5 +173,3 @@ def find_or_create_account(name, email, password, gm_level=9):
|
|||||||
db.session.add(play_key)
|
db.session.add(play_key)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
return # account
|
return # account
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import zlib
|
|||||||
import xmltodict
|
import xmltodict
|
||||||
import os
|
import os
|
||||||
import app.pylddlib as ldd
|
import app.pylddlib as ldd
|
||||||
|
import pathlib
|
||||||
|
|
||||||
property_blueprint = Blueprint('properties', __name__)
|
property_blueprint = Blueprint('properties', __name__)
|
||||||
|
|
||||||
@ -206,16 +207,16 @@ def get(status="all"):
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@property_blueprint.route('/view_model/<id>', methods=['GET'])
|
@property_blueprint.route('/view_model/<id>/<lod>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def view_model(id):
|
def view_model(id, lod):
|
||||||
property_content_data = PropertyContent.query.filter(PropertyContent.id==id).all()
|
property_content_data = PropertyContent.query.filter(PropertyContent.id==id).all()
|
||||||
|
|
||||||
# TODO: Restrict somehow
|
# TODO: Restrict somehow
|
||||||
formatted_data = [
|
formatted_data = [
|
||||||
{
|
{
|
||||||
"obj": url_for('properties.get_model', id=property_content_data[0].id, file_format='obj'),
|
"obj": url_for('properties.get_model', id=property_content_data[0].id, file_format='obj', lod=lod),
|
||||||
"mtl": url_for('properties.get_model', id=property_content_data[0].id, file_format='mtl'),
|
"mtl": url_for('properties.get_model', id=property_content_data[0].id, file_format='mtl', lod=lod),
|
||||||
"lot": property_content_data[0].lot,
|
"lot": property_content_data[0].lot,
|
||||||
"id": property_content_data[0].id,
|
"id": property_content_data[0].id,
|
||||||
"pos": [{
|
"pos": [{
|
||||||
@ -232,7 +233,8 @@ def view_model(id):
|
|||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'ldd/ldd.html.j2',
|
'ldd/ldd.html.j2',
|
||||||
content=formatted_data
|
content=formatted_data,
|
||||||
|
lod=lod
|
||||||
)
|
)
|
||||||
|
|
||||||
property_center = {
|
property_center = {
|
||||||
@ -245,9 +247,9 @@ property_center = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@property_blueprint.route('/view_models/<id>', methods=['GET'])
|
@property_blueprint.route('/view_models/<id>/<lod>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def view_models(id):
|
def view_models(id, lod):
|
||||||
property_content_data = PropertyContent.query.filter(
|
property_content_data = PropertyContent.query.filter(
|
||||||
PropertyContent.property_id==id
|
PropertyContent.property_id==id
|
||||||
).order_by(PropertyContent.lot).all()
|
).order_by(PropertyContent.lot).all()
|
||||||
@ -273,8 +275,8 @@ def view_models(id):
|
|||||||
# add new lot
|
# add new lot
|
||||||
consolidated_list.append(
|
consolidated_list.append(
|
||||||
{
|
{
|
||||||
"obj": url_for('properties.get_model', id=property_content_data[item].id, file_format='obj'),
|
"obj": url_for('properties.get_model', id=property_content_data[item].id, file_format='obj', lod=lod),
|
||||||
"mtl": url_for('properties.get_model', id=property_content_data[item].id, file_format='mtl'),
|
"mtl": url_for('properties.get_model', id=property_content_data[item].id, file_format='mtl', lod=lod),
|
||||||
"lot": property_content_data[item].lot,
|
"lot": property_content_data[item].lot,
|
||||||
"id": property_content_data[item].id,
|
"id": property_content_data[item].id,
|
||||||
"pos": [{
|
"pos": [{
|
||||||
@ -293,18 +295,20 @@ def view_models(id):
|
|||||||
'ldd/ldd.html.j2',
|
'ldd/ldd.html.j2',
|
||||||
property_data=property_data,
|
property_data=property_data,
|
||||||
content=consolidated_list,
|
content=consolidated_list,
|
||||||
center=property_center[property_data.zone_id]
|
center=property_center[property_data.zone_id],
|
||||||
|
lod=lod
|
||||||
)
|
)
|
||||||
|
|
||||||
@property_blueprint.route('/get_model/<id>/<file_format>', methods=['GET'])
|
@property_blueprint.route('/get_model/<id>/<file_format>/<lod>', methods=['GET'])
|
||||||
@login_required
|
@login_required
|
||||||
def get_model(id, file_format):
|
def get_model(id, file_format, lod):
|
||||||
content = PropertyContent.query.filter(PropertyContent.id==id).first()
|
content = PropertyContent.query.filter(PropertyContent.id==id).first()
|
||||||
|
if not(0 <= int(lod) <= 2):
|
||||||
|
abort(404)
|
||||||
if content.lot == 14: # ugc model
|
if content.lot == 14: # ugc model
|
||||||
response = ugc(content)[0]
|
response = ugc(content)[0]
|
||||||
else: # prebuild model
|
else: # prebuild model
|
||||||
response = prebuilt(content, file_format)[0]
|
response = prebuilt(content, file_format, lod)[0]
|
||||||
|
|
||||||
response.headers.set('Content-Type', 'text/xml')
|
response.headers.set('Content-Type', 'text/xml')
|
||||||
return response
|
return response
|
||||||
@ -337,7 +341,7 @@ def ugc(content):
|
|||||||
return response, ugc_data.filename
|
return response, ugc_data.filename
|
||||||
|
|
||||||
|
|
||||||
def prebuilt(content, file_format):
|
def prebuilt(content, file_format, lod):
|
||||||
# translate LOT to component id
|
# translate LOT to component id
|
||||||
# we need to get a type of 2 because reasons
|
# we need to get a type of 2 because reasons
|
||||||
render_component_id = query_cdclient(
|
render_component_id = query_cdclient(
|
||||||
@ -357,7 +361,7 @@ def prebuilt(content, file_format):
|
|||||||
return f"No filename for LOT {content.lot}"
|
return f"No filename for LOT {content.lot}"
|
||||||
|
|
||||||
if file_format == "lxfml":
|
if file_format == "lxfml":
|
||||||
lxfml = f'app/luclient/res/BrickModels/{filename.split(".")[0]}.lxfml'
|
lxfml = pathilob.Path(f'app/luclient/res/BrickModels/{filename.split(".")[0]}.lxfml')
|
||||||
with open(lxfml, 'r') as file:
|
with open(lxfml, 'r') as file:
|
||||||
lxfml_data = file.read()
|
lxfml_data = file.read()
|
||||||
# print(lxfml_data)
|
# print(lxfml_data)
|
||||||
@ -365,21 +369,15 @@ def prebuilt(content, file_format):
|
|||||||
|
|
||||||
elif file_format in ["obj", "mtl"]:
|
elif file_format in ["obj", "mtl"]:
|
||||||
|
|
||||||
cache = f"app/cache/{filename}.{file_format}"
|
cache = f"app/cache/BrickModels/{filename}.lod{lod}.{file_format}"
|
||||||
|
|
||||||
if os.path.exists(cache):
|
if not os.path.exists(cache):
|
||||||
with open(cache, 'r') as file:
|
|
||||||
cache_data = file.read()
|
|
||||||
response = make_response(cache_data)
|
|
||||||
|
|
||||||
else:
|
|
||||||
lxfml = f'app/luclient/res/BrickModels/{filename.split(".")[0]}.lxfml'
|
lxfml = f'app/luclient/res/BrickModels/{filename.split(".")[0]}.lxfml'
|
||||||
ldd.main(lxfml, cache.split('.')[0]) # convert to OBJ
|
ldd.main(lxfml, cache.split('.')[0]) # convert to OBJ
|
||||||
|
|
||||||
if os.path.exists(cache):
|
with open(cache, 'r') as file:
|
||||||
with open(cache, 'r') as file:
|
cache_data = file.read()
|
||||||
cache_data = file.read()
|
response = make_response(cache_data)
|
||||||
response = make_response(cache_data)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
raise(Exception("INVALID FILE FORMAT"))
|
raise(Exception("INVALID FILE FORMAT"))
|
||||||
|
@ -30,7 +30,7 @@ if sys.version_info < (3, 0):
|
|||||||
sys.setdefaultencoding('utf-8')
|
sys.setdefaultencoding('utf-8')
|
||||||
|
|
||||||
PRIMITIVEPATH = '/Primitives/'
|
PRIMITIVEPATH = '/Primitives/'
|
||||||
GEOMETRIEPATH = PRIMITIVEPATH + 'LOD0/'
|
GEOMETRIEPATH = PRIMITIVEPATH
|
||||||
DECORATIONPATH = '/Decorations/'
|
DECORATIONPATH = '/Decorations/'
|
||||||
MATERIALNAMESPATH = '/MaterialNames/'
|
MATERIALNAMESPATH = '/MaterialNames/'
|
||||||
|
|
||||||
@ -238,10 +238,10 @@ class Scene:
|
|||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'BrickSet':
|
if childnode.nodeName == 'BrickSet':
|
||||||
self.Version = str(childnode.getAttribute('version'))
|
self.Version = str(childnode.getAttribute('version'))
|
||||||
elif node.nodeName == 'Cameras':
|
# elif node.nodeName == 'Cameras':
|
||||||
for childnode in node.childNodes:
|
# for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'Camera':
|
# if childnode.nodeName == 'Camera':
|
||||||
self.Scenecamera.append(SceneCamera(node=childnode))
|
# self.Scenecamera.append(SceneCamera(node=childnode))
|
||||||
elif node.nodeName == 'Bricks':
|
elif node.nodeName == 'Bricks':
|
||||||
for childnode in node.childNodes:
|
for childnode in node.childNodes:
|
||||||
if childnode.nodeName == 'Brick':
|
if childnode.nodeName == 'Brick':
|
||||||
@ -720,8 +720,10 @@ class Converter:
|
|||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
out = open(filename + ".obj.tmp", "w+")
|
out = open(filename + ".obj.tmp", "w+")
|
||||||
|
out.truncate(0)
|
||||||
out.write("mtllib " + filename + ".mtl" + '\n\n')
|
out.write("mtllib " + filename + ".mtl" + '\n\n')
|
||||||
outtext = open(filename + ".mtl.tmp", "w+")
|
outtext = open(filename + ".mtl.tmp", "w+")
|
||||||
|
outtext.truncate(0)
|
||||||
|
|
||||||
total = len(self.scene.Bricks)
|
total = len(self.scene.Bricks)
|
||||||
current = 0
|
current = 0
|
||||||
@ -823,13 +825,13 @@ class Converter:
|
|||||||
sys.stdout.write('%s\r' % (' '))
|
sys.stdout.write('%s\r' % (' '))
|
||||||
# print("--- %s seconds ---" % (time.time() - start_time))
|
# print("--- %s seconds ---" % (time.time() - start_time))
|
||||||
|
|
||||||
def setDBFolderVars(dbfolderlocation):
|
def setDBFolderVars(dbfolderlocation, lod):
|
||||||
global PRIMITIVEPATH
|
global PRIMITIVEPATH
|
||||||
global GEOMETRIEPATH
|
global GEOMETRIEPATH
|
||||||
global DECORATIONPATH
|
global DECORATIONPATH
|
||||||
global MATERIALNAMESPATH
|
global MATERIALNAMESPATH
|
||||||
PRIMITIVEPATH = os.path.join(dbfolderlocation, 'Primitives', '')
|
PRIMITIVEPATH = os.path.join(dbfolderlocation, 'Primitives', '')
|
||||||
GEOMETRIEPATH = os.path.join(dbfolderlocation, 'brickprimitives', 'lod0', '')
|
GEOMETRIEPATH = os.path.join(dbfolderlocation, 'brickprimitives', f'lod{lod}', '')
|
||||||
DECORATIONPATH = os.path.join(dbfolderlocation, 'Decorations', '')
|
DECORATIONPATH = os.path.join(dbfolderlocation, 'Decorations', '')
|
||||||
MATERIALNAMESPATH = os.path.join(dbfolderlocation, 'MaterialNames', '')
|
MATERIALNAMESPATH = os.path.join(dbfolderlocation, 'MaterialNames', '')
|
||||||
# print(MATERIALNAMESPATH)
|
# print(MATERIALNAMESPATH)
|
||||||
@ -880,7 +882,7 @@ def progress(count, total, status='', suffix = ''):
|
|||||||
sys.stdout.write('Progress: [%s] %s%s %s %s\r' % (bar, percents, '%', suffix, status))
|
sys.stdout.write('Progress: [%s] %s%s %s %s\r' % (bar, percents, '%', suffix, status))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
def main(lxf_filename, obj_filename):
|
def main(lxf_filename, obj_filename, lod="2"):
|
||||||
# print("- - - pylddlib - - -")
|
# print("- - - pylddlib - - -")
|
||||||
# print(" _ ")
|
# print(" _ ")
|
||||||
# print(" [_]")
|
# print(" [_]")
|
||||||
@ -890,10 +892,11 @@ def main(lxf_filename, obj_filename):
|
|||||||
# print(" [=|=]")
|
# print(" [=|=]")
|
||||||
# print("")
|
# print("")
|
||||||
# print("- - - - - - - - - - - -")
|
# print("- - - - - - - - - - - -")
|
||||||
|
global GEOMETRIEPATH
|
||||||
|
GEOMETRIEPATH = GEOMETRIEPATH + f"LOD{lod}/"
|
||||||
converter = Converter()
|
converter = Converter()
|
||||||
# print("Found DB folder. Will use this instead of db.lif!")
|
# print("Found DB folder. Will use this instead of db.lif!")
|
||||||
setDBFolderVars(dbfolderlocation = "app/luclient/res/")
|
setDBFolderVars(dbfolderlocation = "app/luclient/res/", lod=lod)
|
||||||
converter.LoadDBFolder(dbfolderlocation = "app/luclient/res/")
|
converter.LoadDBFolder(dbfolderlocation = "app/luclient/res/")
|
||||||
converter.LoadScene(filename=lxf_filename)
|
converter.LoadScene(filename=lxf_filename)
|
||||||
converter.Export(filename=obj_filename)
|
converter.Export(filename=obj_filename)
|
||||||
|
@ -467,16 +467,16 @@
|
|||||||
constructor(designID, database){
|
constructor(designID, database){
|
||||||
this.designID = designID
|
this.designID = designID
|
||||||
this.Parts = []
|
this.Parts = []
|
||||||
|
|
||||||
this.studsFields2D = []
|
this.studsFields2D = []
|
||||||
let GeometryLocation = `${designID}.g`
|
let lod = {{ lod }}
|
||||||
|
let GeometryLocation = `lod${lod}/${designID}.g`
|
||||||
let PrimitiveLocation = `${designID}.xml`
|
let PrimitiveLocation = `${designID}.xml`
|
||||||
|
|
||||||
let GeometryCount = 0
|
let GeometryCount = 0
|
||||||
while (GeometryLocation in database.filelist) {
|
while (GeometryLocation in database.filelist) {
|
||||||
this.Parts[GeometryCount] = new GeometryReader(database.filelist[GeometryLocation].read())
|
this.Parts[GeometryCount] = new GeometryReader(database.filelist[GeometryLocation].read())
|
||||||
GeometryCount = GeometryCount + 1
|
GeometryCount = GeometryCount + 1
|
||||||
GeometryLocation = `${designID}.g${GeometryCount}`
|
GeometryLocation = `lod${lod}/${designID}.g${GeometryCount}`
|
||||||
}
|
}
|
||||||
let primitive = new Primitive(database.filelist[PrimitiveLocation].read())
|
let primitive = new Primitive(database.filelist[PrimitiveLocation].read())
|
||||||
this.Partname = primitive.Designname
|
this.Partname = primitive.Designname
|
||||||
@ -1019,7 +1019,7 @@
|
|||||||
return self.filelist[filename];
|
return self.filelist[filename];
|
||||||
}
|
}
|
||||||
|
|
||||||
parse(dburl) {
|
parse(dburl, folder="") {
|
||||||
let self = this;
|
let self = this;
|
||||||
let xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
xhr.open('GET', dburl, false);
|
xhr.open('GET', dburl, false);
|
||||||
@ -1038,10 +1038,16 @@
|
|||||||
let obj = data[i];
|
let obj = data[i];
|
||||||
if (obj.type == 'directory'){
|
if (obj.type == 'directory'){
|
||||||
// parse subdirs
|
// parse subdirs
|
||||||
self.parse(dburl + obj.name + '/')
|
self.parse(dburl + obj.name + '/', obj.name)
|
||||||
}
|
}
|
||||||
else if (obj.type == 'file'){
|
else if (obj.type == 'file'){
|
||||||
self.filelist[obj.name] = new DBURLFile(dburl + obj.name, obj.name)
|
|
||||||
|
if (folder.includes("lod")){
|
||||||
|
|
||||||
|
self.filelist[`${folder}/${obj.name}`] = new DBURLFile(dburl + obj.name, obj.name)
|
||||||
|
} else {
|
||||||
|
self.filelist[obj.name] = new DBURLFile(dburl + obj.name, obj.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log('Strange object parsed: ' + obj.type)
|
console.log('Strange object parsed: ' + obj.type)
|
||||||
@ -1063,7 +1069,7 @@
|
|||||||
let lxfml_file_list = [
|
let lxfml_file_list = [
|
||||||
{% for model in content %}
|
{% for model in content %}
|
||||||
{% if model.lot == 14 %}
|
{% if model.lot == 14 %}
|
||||||
"{{url_for('properties.get_model', id=model.id, file_format='lxfml')}}"{{ ", " if not loop.last else "" }}
|
"{{url_for('properties.get_model', id=model.id, file_format='lxfml', lod=lod)}}"{{ ", " if not loop.last else "" }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
]
|
]
|
||||||
|
@ -81,11 +81,24 @@
|
|||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<br/>
|
<br/>
|
||||||
|
<h5 class="text-center">Render Quality</h5>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<a role="button" class="btn btn-primary btn-block"
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
href='{{ url_for('properties.view_models', id=property.id) }}'>
|
href='{{ url_for('properties.view_models', id=property.id, lod=0) }}'>
|
||||||
Render Property
|
High (0)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col text-center">
|
||||||
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
|
href='{{ url_for('properties.view_models', id=property.id, lod=1) }}'>
|
||||||
|
Med (1)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col text-center">
|
||||||
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
|
href='{{ url_for('properties.view_models', id=property.id, lod=2) }}'>
|
||||||
|
Low (2)
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,21 +44,12 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<a role="button" class="btn btn-primary btn-block"
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
href='{{ url_for('properties.get_model', id=item.id, file_format="lxfml") }}'>
|
href='{{ url_for('properties.get_model', id=item.id, file_format="lxfml", lod=0) }}'>
|
||||||
View Model XML
|
View Model XML
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<div class="row">
|
|
||||||
<div class="col text-center">
|
|
||||||
<a role="button" class="btn btn-primary btn-block"
|
|
||||||
href='{{ url_for('properties.view_model', id=item.id) }}'>
|
|
||||||
Render Model
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
<a role="button" class="btn btn-primary btn-block"
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
@ -67,5 +58,27 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<br/>
|
||||||
|
<h5 class="text-center">Render Quality</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col text-center">
|
||||||
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
|
href='{{ url_for('properties.view_model', id=item.id, lod=0) }}'>
|
||||||
|
High (0)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col text-center">
|
||||||
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
|
href='{{ url_for('properties.view_model', id=item.id, lod=1) }}'>
|
||||||
|
Med (1)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col text-center">
|
||||||
|
<a role="button" class="btn btn-primary btn-block"
|
||||||
|
href='{{ url_for('properties.view_model', id=item.id, lod=2) }}'>
|
||||||
|
Low (2)
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user