Merge pull request #3 from lopezloo/ui-overhaul

UI overhaul
This commit is contained in:
aap 2023-02-10 10:58:11 +01:00 committed by GitHub
commit d3f78b364e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 409 additions and 46 deletions

View File

@ -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 class="viewer-panel">
<canvas id="glcanvas"></canvas>
<table class="ui" id="colors">
<!-- JS inserts colors here -->
</table>
<div class="frames-wrapper ui">
<ul id="frames">
<!-- JS inserts frames here -->
</ul>
</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>
<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 class="select-panel ui">
<div id="control">
<a id="game-select-iii" href="javascript: startVehicleViewerIII(defaultModel);">III</a> |
<a id="game-select-vc" href="javascript: startVehicleViewerVC(defaultModel);">VC</a> |
<a id="game-select-sa" href="javascript: startVehicleViewerSA(defaultModel);">SA</a>
</div>
<div class="objects-wrapper">
<select id="objects" size="25">
<!-- JS inserts models here -->
</select>
</div>
</div>
<table id="colors" style="float:left">
<!-- JS inserts colors here -->
</table>
<div style="display:table;">
<ul id="frames">
<!-- JS inserts frames here -->
</ul>
</div>
<div style="clear:both;"></div>
<ul class="bottom-links ui">
<li>Press I to toggle 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';
@ -62,6 +86,9 @@ startVehicleViewerIII(model)
else {
SelectModel(model);
}
uiSetCurrentGame("iii");
uiSetCurrentModel(CurrentModel.model);
});
}
@ -80,6 +107,9 @@ startVehicleViewerVC(model)
else {
SelectModel(model);
}
uiSetCurrentGame("vc");
uiSetCurrentModel(CurrentModel.model);
});
}
@ -98,6 +128,9 @@ startVehicleViewerSA(model)
else {
SelectModel(model);
}
uiSetCurrentGame("sa");
uiSetCurrentModel(CurrentModel.model);
});
}
@ -130,5 +163,5 @@ else if(initialGame === 'vc') {
else if(initialGame === 'sa') {
startVehicleViewerSA(initialModel);
}
</script>
</script>
</html>

View File

@ -218,4 +218,4 @@ loadVehicleViewer(idefile, CB)
CB();
});
});
}
}

85
main.js
View File

@ -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(!wheel && f.name.startsWith("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
View File

@ -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)
{

101
ui.js Normal file
View File

@ -0,0 +1,101 @@
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);
function
uiSetCurrentGame(game) {
document.querySelectorAll("#control a").forEach((v) => {
v.classList.remove("active");
});
let gameSelect = document.getElementById("game-select-" + game);
gameSelect.classList.add("active");
}
function
uiSetCurrentModel(model) {
let l = document.querySelectorAll("#objects option");
for(let i = 0; i < l.length; i++) {
if(l[i].value === model) {
l[i].selected = 'selected';
break;
}
}
}

168
webgl.css
View File

@ -1,7 +1,167 @@
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;
background-color: white;
color: black;
font-family: Arial;
font-size: 18px;
font-weight: bold;
padding-top: 5px;
padding-bottom: 5px;
}
.objects-wrapper {
float: left;
height: calc(100% - 15px);
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;
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;
}
#control a {
text-decoration: none;
}
#control a:hover, #control a.active {
text-decoration: underline;
}
@media (prefers-color-scheme: dark)
{
body, canvas {
background-color: #181818;
}
body, a, #objects, option {
color: #f5f5f5 !important;
}
#objects {
background-color: #292929;
}
option:checked, option:hover, .option:active {
background-color: #4f4f4f !important;
}
#colors, .custom-colors input {
background-color: #343434;
}
#colors td {
border: 1px solid white;
}
.custom-colors input {
border-radius: 2px;
}
#objects option:nth-child(2n) {
background-color: #2e2e2e;
}
#control {
background-color: #292929;
color: #f5f5f5;
}
}