1
0
Fork 0

added fastcubes and a better readme

This commit is contained in:
QbeRoot 2021-11-06 03:24:44 +01:00
parent 2a5488e663
commit b344d0109c
2 changed files with 102 additions and 27 deletions

View file

@ -1,2 +1,11 @@
# sms-livecol
A live collision viewer for Super Mario Sunshine running on Dolphin.
A live collision viewer for Super Mario Sunshine running on Dolphin.
## Installation
Install Python 3.9 or higher, and use `pip` to install the following packages:
```
pip install numpy PyOpenGL PyQt5 pyrr
```
## Usage
Start the program by running `collision.py` (or the `run` script that matches your system). Make sure Dolphin is open and running any version of Super Mario Sunshine, then click "Connect to Dolphin".

View file

@ -1,5 +1,7 @@
import sys, pyrr
from enum import IntEnum
from PyQt5 import QtCore
from PyQt5 import QtGui
from PyQt5 import QtWidgets
@ -14,8 +16,11 @@ from numpy import array
from memorylib import Dolphin
PlaneType = IntEnum('SurfaceType', 'FLOOR WATER ROOF WALLZ WALLX CUBE')
class CollisionViewer(QtWidgets.QOpenGLWidget):
gpCamera = 0
gpCubeFastA = 0
gpMapCollisionData = 0
def __init__(self, dolphin: Dolphin, parent=None):
@ -26,8 +31,10 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
self.frameSwapped.connect(self.update)
def initializeGL(self) -> None:
glEnable(GL_DEPTH_TEST)
glEnable(GL_BLEND)
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
glClearColor(0.7, 0.7, 1.0, 0.0)
self.shader = shaders.compileProgram(
@ -38,19 +45,26 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
layout (location = 0) in vec3 position;
layout (location = 1) in float type;
out vec4 vBorderColor;
out vec4 vVertexColor;
void main() {
gl_Position = projMat * viewMat * vec4(position, 1.0);
vBorderColor = vec4(0, 0, 0, 1);
if (type == 0) {
if (type == """ + str(int(PlaneType.FLOOR)) + """) {
vVertexColor = vec4(0, 0, 1, 1);
} else if (type == 1) {
} else if (type == """ + str(int(PlaneType.WATER)) + """) {
vVertexColor = vec4(0, 0, 1, 1); // TODO: transparency without breaking the depth test
} else if (type == """ + str(int(PlaneType.ROOF)) + """) {
vVertexColor = vec4(1, 0, 0, 1);
} else if (type == 2) {
} else if (type == """ + str(int(PlaneType.WALLZ)) + """) {
vVertexColor = vec4(0, 1, 0, 1);
} else if (type == 3) {
} else if (type == """ + str(int(PlaneType.WALLX)) + """) {
vVertexColor = vec4(0, 0.5, 0, 1);
} else if (type == """ + str(int(PlaneType.CUBE)) + """) {
vBorderColor = vVertexColor = vec4(1, 0.5, 0, 0.5);
} else {
vVertexColor = vec4(0.5, 0.5, 0.5, 1);
}
@ -59,9 +73,11 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;
in vec4 vBorderColor[3];
in vec4 vVertexColor[3];
out vec3 gTriDistance;
out float gTriSize;
out vec4 gBorderColor;
out vec4 gVertexColor;
void main() {
@ -70,16 +86,19 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
distance(gl_in[1].gl_Position, gl_in[2].gl_Position));
gTriDistance = vec3(1, 0, 0);
gBorderColor = vBorderColor[0];
gVertexColor = vVertexColor[0];
gl_Position = gl_in[0].gl_Position;
EmitVertex();
gTriDistance = vec3(0, 1, 0);
gBorderColor = vBorderColor[1];
gVertexColor = vVertexColor[1];
gl_Position = gl_in[1].gl_Position;
EmitVertex();
gTriDistance = vec3(0, 0, 1);
gBorderColor = vBorderColor[2];
gVertexColor = vVertexColor[2];
gl_Position = gl_in[2].gl_Position;
EmitVertex();
@ -89,6 +108,7 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
shaders.compileShader("""#version 330 core
in vec3 gTriDistance;
in float gTriSize;
in vec4 gBorderColor;
in vec4 gVertexColor;
out vec4 color;
@ -101,7 +121,8 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
void main() {
float d1 = min(min(gTriDistance.x, gTriDistance.y), gTriDistance.z);
color = smoothstep(0, fwidth(d1), d1) * gVertexColor;
float step = smoothstep(0, fwidth(d1), d1);
color = step * gVertexColor + (1 - step) * gBorderColor;
}""", GL_FRAGMENT_SHADER))
self.vao = glGenVertexArrays(1)
@ -134,6 +155,11 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
[self.dolphin.read_float(camera + 0x124), self.dolphin.read_float(camera + 0x128), self.dolphin.read_float(camera + 0x12C)],
[self.dolphin.read_float(camera + 0x148), self.dolphin.read_float(camera + 0x14C), self.dolphin.read_float(camera + 0x150)],
[self.dolphin.read_float(camera + 0x30), self.dolphin.read_float(camera + 0x34), self.dolphin.read_float(camera + 0x38)])
floors = set()
roofs = set()
walls = set()
cubes = set()
mapColData = self.dolphin.read_uint32(self.gpMapCollisionData)
if mapColData == 0:
@ -143,10 +169,6 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
checkLists1 = self.dolphin.read_uint32(mapColData + 0x14)
checkLists2 = self.dolphin.read_uint32(mapColData + 0x18)
floors = set()
roofs = set()
walls = set()
for i in range(checkListCount):
if checkLists1 != 0:
floors |= self.getCheckData(self.dolphin.read_uint32(checkLists1 + 0x24 * i + 0x4))
@ -158,28 +180,72 @@ class CollisionViewer(QtWidgets.QOpenGLWidget):
roofs |= self.getCheckData(self.dolphin.read_uint32(checkLists2 + 0x24 * i + 0x10))
walls |= self.getCheckData(self.dolphin.read_uint32(checkLists2 + 0x24 * i + 0x1C))
for i in range(3):
cube = self.dolphin.read_uint32(self.gpCubeFastA + 4 * i)
if cube < 0x80000000:
continue
length = self.dolphin.read_uint8(cube + 0x10)
infoptr = self.dolphin.read_uint32(cube + 0x14)
if infoptr < 0x80000000:
continue
info = self.dolphin.read_uint32(infoptr + 0x10)
if info < 0x80000000:
continue
for j in range(length):
cubes.add(self.dolphin.read_uint32(info + 4 * j))
buffer = []
for f in floors:
ptype = PlaneType.WATER if self.dolphin.read_uint16(f) in [0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x4104] else PlaneType.FLOOR
buffer += [
[self.dolphin.read_float(f + 0x10), self.dolphin.read_float(f + 0x14), self.dolphin.read_float(f + 0x18), 0],
[self.dolphin.read_float(f + 0x1C), self.dolphin.read_float(f + 0x20), self.dolphin.read_float(f + 0x24), 0],
[self.dolphin.read_float(f + 0x28), self.dolphin.read_float(f + 0x2C), self.dolphin.read_float(f + 0x30), 0]
[self.dolphin.read_float(f + 0x10), self.dolphin.read_float(f + 0x14), self.dolphin.read_float(f + 0x18), ptype],
[self.dolphin.read_float(f + 0x1C), self.dolphin.read_float(f + 0x20), self.dolphin.read_float(f + 0x24), ptype],
[self.dolphin.read_float(f + 0x28), self.dolphin.read_float(f + 0x2C), self.dolphin.read_float(f + 0x30), ptype]
]
for r in roofs:
buffer += [
[self.dolphin.read_float(r + 0x10), self.dolphin.read_float(r + 0x14), self.dolphin.read_float(r + 0x18), 1],
[self.dolphin.read_float(r + 0x1C), self.dolphin.read_float(r + 0x20), self.dolphin.read_float(r + 0x24), 1],
[self.dolphin.read_float(r + 0x28), self.dolphin.read_float(r + 0x2C), self.dolphin.read_float(r + 0x30), 1]
[self.dolphin.read_float(r + 0x10), self.dolphin.read_float(r + 0x14), self.dolphin.read_float(r + 0x18), PlaneType.ROOF],
[self.dolphin.read_float(r + 0x1C), self.dolphin.read_float(r + 0x20), self.dolphin.read_float(r + 0x24), PlaneType.ROOF],
[self.dolphin.read_float(r + 0x28), self.dolphin.read_float(r + 0x2C), self.dolphin.read_float(r + 0x30), PlaneType.ROOF]
]
for w in walls:
proj = 3 if self.dolphin.read_uint16(w + 0x4) & 0x8 else 2
ptype = PlaneType.WALLX if self.dolphin.read_uint16(w + 0x4) & 0x8 else PlaneType.WALLZ
buffer += [
[self.dolphin.read_float(w + 0x10), self.dolphin.read_float(w + 0x14), self.dolphin.read_float(w + 0x18), proj],
[self.dolphin.read_float(w + 0x1C), self.dolphin.read_float(w + 0x20), self.dolphin.read_float(w + 0x24), proj],
[self.dolphin.read_float(w + 0x28), self.dolphin.read_float(w + 0x2C), self.dolphin.read_float(w + 0x30), proj]
[self.dolphin.read_float(w + 0x10), self.dolphin.read_float(w + 0x14), self.dolphin.read_float(w + 0x18), ptype],
[self.dolphin.read_float(w + 0x1C), self.dolphin.read_float(w + 0x20), self.dolphin.read_float(w + 0x24), ptype],
[self.dolphin.read_float(w + 0x28), self.dolphin.read_float(w + 0x2C), self.dolphin.read_float(w + 0x30), ptype]
]
for c in cubes:
cx, cy, cz = self.dolphin.read_float(c + 0xC), self.dolphin.read_float(c + 0x10), self.dolphin.read_float(c + 0x14)
dx, dy, dz = self.dolphin.read_float(c + 0x24), self.dolphin.read_float(c + 0x28), self.dolphin.read_float(c + 0x2C)
v = [
[cx - .5 * dx, cy, cz - .5 * dz, PlaneType.CUBE], [cx - .5 * dx, cy + dy, cz - .5 * dz, PlaneType.CUBE],
[cx - .5 * dx, cy, cz + .5 * dz, PlaneType.CUBE], [cx - .5 * dx, cy + dy, cz + .5 * dz, PlaneType.CUBE],
[cx + .5 * dx, cy, cz + .5 * dz, PlaneType.CUBE], [cx + .5 * dx, cy + dy, cz + .5 * dz, PlaneType.CUBE],
[cx + .5 * dx, cy, cz - .5 * dz, PlaneType.CUBE], [cx + .5 * dx, cy + dy, cz - .5 * dz, PlaneType.CUBE]
]
buffer += [
v[0], v[1], v[2], v[1], v[3], v[2], # inward -x
v[2], v[3], v[4], v[3], v[5], v[4], # inward +z
v[4], v[5], v[6], v[5], v[7], v[6], # inward +x
v[6], v[7], v[0], v[7], v[1], v[0], # inward -z
v[0], v[2], v[4], v[0], v[4], v[6], # inward -y
v[1], v[5], v[3], v[1], v[7], v[5], # inward +y
v[0], v[2], v[1], v[1], v[2], v[3], # outward -x
v[2], v[4], v[3], v[3], v[4], v[5], # outward +z
v[4], v[6], v[5], v[5], v[6], v[7], # outward +x
v[6], v[0], v[7], v[7], v[0], v[1], # outward -z
v[0], v[4], v[2], v[0], v[6], v[4], # outward -y
v[1], v[3], v[5], v[1], v[5], v[7], # outward +y
]
glUseProgram(self.shader)
@ -222,12 +288,12 @@ def connect():
status.showMessage('Current game is not Sunshine')
return
viewer.gpCamera, viewer.gpMapCollisionData = {
0x23: (0x8040B370, 0x8040A578), # JP 1.0
0xA3: (0x8040D0A8, 0x8040DEA0), # NA / KOR
0x41: (0x80404808, 0x80405568), # PAL
0x80: (0x803FFA38, 0x803FED40), # JP 1.1
0x4D: (0x80401D08, 0x80402A68), # 3DAS
viewer.gpCamera, viewer.gpCubeFastA, viewer.gpMapCollisionData = {
0x23: (0x8040B370, 0x8040B3B0, 0x8040A578), # JP 1.0
0xA3: (0x8040D0A8, 0x8040D0E8, 0x8040DEA0), # NA / KOR
0x41: (0x80404808, 0x80404848, 0x80405568), # PAL
0x80: (0x803FFA38, 0x803FFA78, 0x803FED40), # JP 1.1
0x4D: (0x80401D08, 0x80401D48, 0x80402A68), # 3DAS
}.get(dolphin.read_uint8(0x80365DDD))
status.showMessage('Ready')