mirror of
https://github.com/GTAmodding/modelviewjs.git
synced 2025-07-09 02:20:14 +02:00
UI overhaul
This commit is contained in:
parent
b29260e3d6
commit
6b91137253
56
index.html
56
index.html
@ -1,32 +1,54 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>WebGL</title>
|
||||
<title>GTA Model Viewer</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="webgl.css" type="text/css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="control">
|
||||
<a href="javascript: startVehicleViewerIII(defaultModel);">III</a>
|
||||
<a href="javascript: startVehicleViewerVC(defaultModel);">VC</a>
|
||||
<a href="javascript: startVehicleViewerSA(defaultModel);">SA</a>
|
||||
</div>
|
||||
<canvas id="glcanvas" width="640" height="480" style="float:left"></canvas>
|
||||
<div style="float:left">
|
||||
<select id="objects" size="25">
|
||||
<!-- JS inserts models here -->
|
||||
</select>
|
||||
</div>
|
||||
<table id="colors" style="float:left">
|
||||
<div class="viewer-panel">
|
||||
<canvas id="glcanvas"></canvas>
|
||||
|
||||
<table class="ui" id="colors">
|
||||
<!-- JS inserts colors here -->
|
||||
</table>
|
||||
<div style="display:table;">
|
||||
|
||||
<div class="frames-wrapper ui">
|
||||
<ul id="frames">
|
||||
<!-- JS inserts frames here -->
|
||||
</ul>
|
||||
</div>
|
||||
<div style="clear:both;"></div>
|
||||
|
||||
<div class="custom-colors ui">
|
||||
<input type="color" id="custom-color0">
|
||||
<input type="color" id="custom-color1">
|
||||
<input type="color" id="custom-color2">
|
||||
<input type="color" id="custom-color3">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-panel ui">
|
||||
<div id="control">
|
||||
<a href="javascript: startVehicleViewerIII(defaultModel);">III</a>
|
||||
<a href="javascript: startVehicleViewerVC(defaultModel);">VC</a>
|
||||
<a href="javascript: startVehicleViewerSA(defaultModel);">SA</a>
|
||||
</div>
|
||||
|
||||
<div class="objects-wrapper">
|
||||
<select id="objects" size="25">
|
||||
<!-- JS inserts models here -->
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="bottom-links ui">
|
||||
<li>Press I to show/hide interface</li>
|
||||
<li>|</li>
|
||||
<li>
|
||||
<a href="https://github.com/GTAmodding/modelviewjs" id="source-link" target="blank" rel="noopener">Source code</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</body>
|
||||
|
||||
@ -39,6 +61,8 @@
|
||||
<script src="rwstream.js"></script>
|
||||
<script src="main.js"></script>
|
||||
<script src="loaddata.js"></script>
|
||||
<script src="ui.js"></script>
|
||||
|
||||
<script>
|
||||
var defaultModel = 'cheetah';
|
||||
var initialGame = 'iii';
|
||||
@ -130,5 +154,5 @@ else if(initialGame === 'vc') {
|
||||
else if(initialGame === 'sa') {
|
||||
startVehicleViewerSA(initialModel);
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
</html>
|
||||
|
85
main.js
85
main.js
@ -25,6 +25,8 @@ var defaultProgram;
|
||||
var envMapProgram;
|
||||
var carPS2Program;
|
||||
|
||||
var backgroundColor = [0, 0, 0, 0];
|
||||
|
||||
function deg2rad(d) { return d / 180.0 * Math.PI; }
|
||||
|
||||
var rotating, zooming;
|
||||
@ -81,6 +83,15 @@ InitRW()
|
||||
{
|
||||
console.log("InitRW()");
|
||||
let canvas = document.querySelector('#glcanvas');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
// Get background color from stylesheet
|
||||
var bgColorStr = window.getComputedStyle(canvas, null).getPropertyValue("background-color");
|
||||
bgColorStr = bgColorStr.substring(4, bgColorStr.length-1);
|
||||
backgroundColor = bgColorStr.replace(" ", "").split(",");
|
||||
backgroundColor = [parseFloat(backgroundColor[0])/255, parseFloat(backgroundColor[1])/255, parseFloat(backgroundColor[2])/255, 1.0];
|
||||
|
||||
gl = canvas.getContext('webgl');
|
||||
|
||||
if(!gl){
|
||||
@ -159,18 +170,6 @@ displayFrames(frame, parelem)
|
||||
}
|
||||
}
|
||||
|
||||
function
|
||||
putControl()
|
||||
{
|
||||
// let ctl = document.getElementById('control');
|
||||
// let reloadbtn = document.createElement('input');
|
||||
// reloadbtn.type = "button";
|
||||
// reloadbtn.value = "reload";
|
||||
// reloadbtn.onclick = reload;
|
||||
// ctl.appendChild(reloadbtn);
|
||||
}
|
||||
|
||||
|
||||
function
|
||||
loadCarIII(filename)
|
||||
{
|
||||
@ -203,11 +202,11 @@ loadCarSA(filename)
|
||||
setupSACar(myclump);
|
||||
setVehicleColors(modelinfo,
|
||||
carColors[0], carColors[1], carColors[2], carColors[3]);
|
||||
// setVehicleLightColors(modelinfo,
|
||||
// [ 128, 0, 0, 255 ],
|
||||
// [ 128, 0, 0, 255 ],
|
||||
// [ 128, 0, 0, 255 ],
|
||||
// [ 128, 0, 0, 255 ]);
|
||||
setVehicleLightColors(modelinfo,
|
||||
[ 255, 255, 255, 255 ],
|
||||
[ 255, 255, 255, 255 ],
|
||||
[ 255, 255, 255, 255 ],
|
||||
[ 255, 255, 255, 255 ]);
|
||||
main();
|
||||
});
|
||||
}
|
||||
@ -238,8 +237,6 @@ main()
|
||||
if(!running){
|
||||
running = true;
|
||||
|
||||
putControl();
|
||||
|
||||
let then = 0;
|
||||
function render(now){
|
||||
now *= 0.001; // convert to seconds
|
||||
@ -309,6 +306,11 @@ setVehicleColors(vehinfo, c1, c2, c3, c4)
|
||||
vehinfo.thirdMaterials[i].color = c3;
|
||||
for(let i = 0; i < vehinfo.fourthMaterials.length; i++)
|
||||
vehinfo.fourthMaterials[i].color = c4;
|
||||
|
||||
if(c1) document.getElementById("custom-color0").value = RGB2HTML(c1);
|
||||
if(c2) document.getElementById("custom-color1").value = RGB2HTML(c2);
|
||||
if(c3) document.getElementById("custom-color2").value = RGB2HTML(c3);
|
||||
if(c4) document.getElementById("custom-color3").value = RGB2HTML(c4);
|
||||
}
|
||||
|
||||
function
|
||||
@ -362,6 +364,10 @@ processVehicle(clump)
|
||||
fourthLightMaterials: [], // back right
|
||||
clump: clump
|
||||
};
|
||||
|
||||
// Wheel atomic to clone
|
||||
let wheel = null;
|
||||
|
||||
for(let i = 0; i < clump.atomics.length; i++){
|
||||
a = clump.atomics[i];
|
||||
f = a.frame;
|
||||
@ -369,17 +375,41 @@ processVehicle(clump)
|
||||
f.name.endsWith("_lo") ||
|
||||
f.name.endsWith("_vlo"))
|
||||
a.visible = false;
|
||||
|
||||
if(f.name === "wheel") {
|
||||
wheel = a;
|
||||
}
|
||||
|
||||
findEditableMaterials(a.geometry, vehicleInfo);
|
||||
}
|
||||
|
||||
// Clone wheels
|
||||
let frame = clump.frame.child;
|
||||
while(wheel && frame) {
|
||||
if(["wheel_rb_dummy", "wheel_rm_dummy", "wheel_lf_dummy", "wheel_lb_dummy", "wheel_lm_dummy"].includes(frame.name)) {
|
||||
let wheel2 = RpAtomicClone(wheel);
|
||||
mat4.copy(wheel2.frame.ltm, frame.ltm);
|
||||
if(["wheel_lf_dummy", "wheel_lb_dummy", "wheel_lm_dummy"].includes(frame.name)) {
|
||||
// Rotate cloned wheel
|
||||
mat4.rotate(wheel2.frame.ltm, wheel2.frame.ltm, Math.PI, [0, 0, 1]);
|
||||
}
|
||||
frame.child = wheel2.frame;
|
||||
clump.atomics.push(wheel2);
|
||||
}
|
||||
frame = frame.next;
|
||||
}
|
||||
|
||||
return vehicleInfo;
|
||||
}
|
||||
|
||||
function
|
||||
drawScene(deltaTime)
|
||||
{
|
||||
// camYaw += deltaTime;
|
||||
if(window.autoRotateCamera) {
|
||||
camYaw += deltaTime * 0.9;
|
||||
}
|
||||
|
||||
gl.clearColor(0.5, 0.5, 0.5, 1.0);
|
||||
gl.clearColor(backgroundColor[0], backgroundColor[1], backgroundColor[2], 1.0);
|
||||
gl.clearDepth(1.0);
|
||||
gl.enable(gl.DEPTH_TEST);
|
||||
gl.depthFunc(gl.LEQUAL);
|
||||
@ -428,3 +458,16 @@ loadDFF(filename, cb)
|
||||
|
||||
req.send(null);
|
||||
}
|
||||
|
||||
function
|
||||
rgbToCSSString(r, g, b)
|
||||
{
|
||||
return ["rgb(",r,",",g,",",b,")"].join("");
|
||||
}
|
||||
|
||||
function
|
||||
RGB2HTML(color)
|
||||
{
|
||||
let decColor = 0x1000000 + color[2] + 0x100 * color[1] + 0x10000 * color[0];
|
||||
return '#' + decColor.toString(16).substr(1);
|
||||
}
|
||||
|
26
rw.js
26
rw.js
@ -269,6 +269,20 @@ RpAtomicCreate()
|
||||
};
|
||||
}
|
||||
|
||||
function
|
||||
RpAtomicClone(a)
|
||||
{
|
||||
let a2 = RpAtomicCreate();
|
||||
a2.type = a.type;
|
||||
a2.visible = a.visible;
|
||||
a2.frame = RwFrameClone(a.frame);
|
||||
a2.geometry = a.geometry;
|
||||
a2.pipeline = a.pipeline;
|
||||
a2.frame.objects = [];
|
||||
a2.frame.objects[0] = a2;
|
||||
return a2;
|
||||
}
|
||||
|
||||
function
|
||||
RpAtomicSetFrame(a, f)
|
||||
{
|
||||
@ -488,6 +502,18 @@ rwFrameInit(f)
|
||||
mat4.copy(f.ltm, f.matrix);
|
||||
}
|
||||
|
||||
function
|
||||
RwFrameClone(f) {
|
||||
let f2 = RwFrameCreate();
|
||||
mat4.copy(f2.matrix, f.matrix);
|
||||
mat4.copy(f2.ltm, f.ltm);
|
||||
f2.child = f.child;
|
||||
f2.name = f.name;
|
||||
f2.parent = f.parent;
|
||||
f2.root = f.root;
|
||||
return f2;
|
||||
}
|
||||
|
||||
function
|
||||
rpMaterialInit(m)
|
||||
{
|
||||
|
78
ui.js
Normal file
78
ui.js
Normal file
@ -0,0 +1,78 @@
|
||||
showInterface = true;
|
||||
autoRotateCamera = false;
|
||||
|
||||
function hex2rgb(hex) {
|
||||
let r = parseInt(hex.slice(1, 3), 16);
|
||||
let g = parseInt(hex.slice(3, 5), 16);
|
||||
let b = parseInt(hex.slice(5, 7), 16);
|
||||
return [r, g, b];
|
||||
}
|
||||
|
||||
function updateVehicleCustomColors() {
|
||||
let colors = [];
|
||||
for(let i = 0; i < 4; i++) {
|
||||
let cStr = document.getElementById("custom-color" + i).value;
|
||||
let c = hex2rgb(cStr);
|
||||
c[3] = 255;
|
||||
colors[i] = c;
|
||||
}
|
||||
setVehicleColors(modelinfo, colors[0], colors[1], colors[2], colors[3]);
|
||||
}
|
||||
|
||||
for(let i = 0; i < 4; i++) {
|
||||
document.getElementById("custom-color" + i).addEventListener("input", updateVehicleCustomColors, false);
|
||||
}
|
||||
|
||||
document.addEventListener("keypress",
|
||||
function(e) {
|
||||
if(e.key === "i") {
|
||||
showInterface = !showInterface;
|
||||
document.querySelectorAll(".ui").forEach((v) => {
|
||||
v.style.visibility = showInterface ? "unset" : "hidden";
|
||||
});
|
||||
}
|
||||
|
||||
else if(e.key === "r") {
|
||||
autoRotateCamera = !autoRotateCamera;
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
||||
document.getElementById("objects").addEventListener("keypress",
|
||||
function(e) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
},
|
||||
false);
|
||||
|
||||
var lastModelChangeViaKey = 0;
|
||||
document.getElementById("objects").addEventListener("keydown",
|
||||
function(e) {
|
||||
if(e.keyCode !== 38 && e.keyCode !== 40) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if(Date.now() - lastModelChangeViaKey < 750) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
lastModelChangeViaKey = Date.now();
|
||||
},
|
||||
false);
|
||||
|
||||
|
||||
document.getElementById("objects").addEventListener("keyup",
|
||||
function(e) {
|
||||
if(e.keyCode !== 38 && e.keyCode !== 40) {
|
||||
return true;
|
||||
}
|
||||
|
||||
lastModelChangeViaKey -= 400;
|
||||
|
||||
let model = document.getElementById("objects").value;
|
||||
if(model !== CurrentModel.model) {
|
||||
SelectModel(model);
|
||||
}
|
||||
},
|
||||
false);
|
143
webgl.css
143
webgl.css
@ -1,7 +1,144 @@
|
||||
canvas {
|
||||
border: 2px solid black;
|
||||
background-color: black;
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
|
||||
body, canvas {
|
||||
background-color: #808080;
|
||||
}
|
||||
|
||||
video {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#objects {
|
||||
outline: none;
|
||||
height: calc(100% - 18.4px);
|
||||
width: 110px;
|
||||
border: unset;
|
||||
}
|
||||
|
||||
.select-panel {
|
||||
position: absolute;
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#control {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.objects-wrapper {
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: calc(100%);
|
||||
}
|
||||
|
||||
.viewer-panel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
option {
|
||||
padding-left: 5px;
|
||||
font-size: 14px;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
option:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#colors {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 130px;
|
||||
|
||||
/*background-color: todo;*/
|
||||
border-radius: 2px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#colors td {
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
#colors td:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.frames-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 100px;
|
||||
}
|
||||
|
||||
.bottom-links {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.bottom-links ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.bottom-links li {
|
||||
float: left;
|
||||
margin-left: 10px;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.custom-colors {
|
||||
position: absolute;
|
||||
bottom: 210px;
|
||||
left: 130px;
|
||||
}
|
||||
|
||||
.custom-colors input:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark)
|
||||
{
|
||||
body, canvas {
|
||||
background-color: #181818;
|
||||
}
|
||||
|
||||
body, a, #objects {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
#objects {
|
||||
background-color: #292929;
|
||||
}
|
||||
|
||||
option:checked, option:hover {
|
||||
background-color: #4f4f4f !important;
|
||||
}
|
||||
|
||||
#colors, .custom-colors input {
|
||||
background-color: #343434;
|
||||
}
|
||||
|
||||
#colors td {
|
||||
border: 1px solid white;
|
||||
}
|
||||
|
||||
.custom-colors input {
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user