Adding modding folder with a hacked build.

This commit is contained in:
ml
2026-09-26 08:53:08 +02:00
parent cdb960dc71
commit c91080aba7
755 changed files with 50424 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
package render
import (
"github.com/inkyblackness/hacked/ui/opengl"
mgl "github.com/go-gl/mathgl/mgl32"
)
// Context provides current render properties.
type Context struct {
OpenGL opengl.OpenGL
ViewMatrix *mgl.Mat4
ProjectionMatrix mgl.Mat4
}
@@ -0,0 +1,39 @@
package render
import (
"math"
"github.com/inkyblackness/imgui-go/v3"
"github.com/inkyblackness/hacked/editor/graphics"
)
// FrameImage renders an image centered and fitted within the given size.
func FrameImage(label string, frameCache *graphics.FrameCache, key graphics.FrameCacheKey, size imgui.Vec2) {
textureID := TextureIDForBitmapFrame(key)
imgui.PushStyleColor(imgui.StyleColorChildBg, imgui.Vec4{X: 0, Y: 0, Z: 0, W: 1})
imgui.PushStyleVarVec2(imgui.StyleVarWindowPadding, imgui.Vec2{X: 0, Y: 0})
if imgui.BeginChildV(label, size, false,
imgui.WindowFlagsNoNav|imgui.WindowFlagsNoInputs|imgui.WindowFlagsNoScrollWithMouse|
imgui.WindowFlagsNoScrollbar) {
texture := frameCache.Texture(key)
if texture != nil {
var uv imgui.Vec2
uv.X, uv.Y = texture.UV()
width, height := texture.Size()
scaleFactor := float32(math.Min(float64(size.X/width), float64(size.Y/height)))
imageSize := imgui.Vec2{X: width * scaleFactor, Y: height * scaleFactor}
bufferSize := imgui.Vec2{X: (size.X - imageSize.X) / 2, Y: (size.Y - imageSize.Y) / 2}
imgui.SetCursorPos(bufferSize)
imgui.ImageV(textureID, imageSize, imgui.Vec2{}, uv,
imgui.Vec4{X: 1, Y: 1, Z: 1, W: 1}, imgui.Vec4{X: 0, Y: 0, Z: 0, W: 0})
}
}
imgui.EndChild()
imgui.PopStyleVar()
imgui.PopStyleColor()
}
@@ -0,0 +1,234 @@
package render
import (
"math"
mgl "github.com/go-gl/mathgl/mgl32"
"github.com/inkyblackness/hacked/ui/opengl"
)
var orientationViewVertexShaderSource = `
#version 150
precision mediump float;
in vec3 vertexPosition;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
out vec3 position;
out float zCenter;
void main(void) {
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(vertexPosition, 1.0);
zCenter = (projectionMatrix * viewMatrix * modelMatrix * vec4(0.0, 0.0, 0.0, 1.0)).z;
position = gl_Position.xyz;
}
`
var orientationViewFragmentShaderSource = `
#version 150
precision mediump float;
uniform vec4 foregroundColor;
uniform vec4 backgroundColor;
in vec3 position;
in float zCenter;
out vec4 fragColor;
void main(void) {
if (position.z <= zCenter)
{
fragColor = foregroundColor;
}
else
{
fragColor = backgroundColor;
}
}
`
// OrientationView is a control that displays how an object is oriented.
// This is still not working properly. The orientation arrow is not properly rotated,
// and I suspect the typical issue of three-angle rotation versus quaternion rotation.
// Though I doubt the original engine used quaternions, it remains too confusing for me.
type OrientationView struct {
context Context
program uint32
vao *opengl.VertexArrayObject
vertexPositionBuffer uint32
vertexPositionAttrib int32
modelMatrixUniform opengl.Matrix4Uniform
viewMatrixUniform opengl.Matrix4Uniform
projectionMatrixUniform opengl.Matrix4Uniform
foregroundColorUniform opengl.Vector4Uniform
backgroundColorUniform opengl.Vector4Uniform
baseOrientation mgl.Mat4
rotation mgl.Vec3
xRingVerticesStart int
yRingVerticesStart int
zRingVerticesStart int
vertices int
}
// NewOrientationView returns a new instance.
func NewOrientationView(context Context, baseOrientation mgl.Mat4, rotation mgl.Vec3) *OrientationView {
gl := context.OpenGL
program, programErr := opengl.LinkNewStandardProgram(gl, orientationViewVertexShaderSource, orientationViewFragmentShaderSource)
if programErr != nil {
panic(opengl.NamedShaderError{Name: "OrientationViewShader", Nested: programErr})
}
view := &OrientationView{
context: context,
program: program,
vao: opengl.NewVertexArrayObject(gl, program),
vertexPositionBuffer: gl.GenBuffers(1)[0],
vertexPositionAttrib: gl.GetAttribLocation(program, "vertexPosition"),
modelMatrixUniform: opengl.Matrix4Uniform(gl.GetUniformLocation(program, "modelMatrix")),
viewMatrixUniform: opengl.Matrix4Uniform(gl.GetUniformLocation(program, "viewMatrix")),
projectionMatrixUniform: opengl.Matrix4Uniform(gl.GetUniformLocation(program, "projectionMatrix")),
foregroundColorUniform: opengl.Vector4Uniform(gl.GetUniformLocation(program, "foregroundColor")),
backgroundColorUniform: opengl.Vector4Uniform(gl.GetUniformLocation(program, "backgroundColor")),
baseOrientation: baseOrientation,
rotation: rotation,
}
{
gl.BindBuffer(opengl.ARRAY_BUFFER, view.vertexPositionBuffer)
var vertices []float32
radius := 0.5
vertices = append(vertices, 0.0, 0.0, 0.0)
vertices = append(vertices, 0.4, 0.0, 0.0)
vertices = append(vertices, 0.0, 0.0, 0.0)
vertices = append(vertices, 0.0, 0.4, 0.0)
vertices = append(vertices, 0.0, 0.0, 0.0)
vertices = append(vertices, 0.0, 0.0, 0.4)
view.xRingVerticesStart = len(vertices)
for angle := 0.0; angle < float64(toRad(360.0)); angle += float64(toRad(4.0)) {
vertices = append(vertices, 0.0, float32(radius*math.Cos(angle)), float32(radius*math.Sin(angle)))
}
vertices = append(vertices, 0.0, float32(radius*math.Cos(0)), float32(radius*math.Sin(0)))
view.yRingVerticesStart = len(vertices)
for angle := 0.0; angle < float64(toRad(360.0)); angle += float64(toRad(4.0)) {
vertices = append(vertices, float32(radius*math.Cos(angle)), 0.0, float32(radius*math.Sin(angle)))
}
vertices = append(vertices, float32(radius*math.Cos(0)), 0.0, float32(radius*math.Sin(0)))
view.zRingVerticesStart = len(vertices)
for angle := 0.0; angle < float64(toRad(360.0)); angle += float64(toRad(4.0)) {
vertices = append(vertices, float32(radius*math.Cos(angle)), float32(radius*math.Sin(angle)), 0.0)
}
vertices = append(vertices, float32(radius*math.Cos(0)), float32(radius*math.Sin(0)), 0.0)
view.vertices = len(vertices)
gl.BufferData(opengl.ARRAY_BUFFER, len(vertices)*4, vertices, opengl.STATIC_DRAW)
gl.BindBuffer(opengl.ARRAY_BUFFER, 0)
}
view.vao.WithSetter(func(gl opengl.OpenGL) {
gl.EnableVertexAttribArray(uint32(view.vertexPositionAttrib))
gl.BindBuffer(opengl.ARRAY_BUFFER, view.vertexPositionBuffer)
gl.VertexAttribOffset(uint32(view.vertexPositionAttrib), 3, opengl.FLOAT, false, 0, 0)
gl.BindBuffer(opengl.ARRAY_BUFFER, 0)
})
return view
}
// Dispose cleans up resources of the view.
func (view *OrientationView) Dispose() {
gl := view.context.OpenGL
view.vao.Dispose()
gl.DeleteBuffers([]uint32{view.vertexPositionBuffer})
gl.DeleteProgram(view.program)
}
func toRad(degree float32) float32 {
return (degree * math.Pi * 2.0) / 360.0
}
// Render renders the orientation view for given orientation.
func (view *OrientationView) Render(orientation mgl.Vec3) {
gl := view.context.OpenGL
view.vao.OnShader(func() {
view.projectionMatrixUniform.Set(gl, &view.context.ProjectionMatrix)
view.viewMatrixUniform.Set(gl, view.context.ViewMatrix)
view.renderRings(false)
view.renderArrow(
mgl.Ident4().
Mul4(mgl.HomogRotate3D(toRad(orientation[0]), mgl.Vec3{view.rotation[0], 0.0, 0.0})).
Mul4(mgl.HomogRotate3D(toRad(orientation[1]), mgl.Vec3{0.0, view.rotation[1], 0.0})).
Mul4(mgl.HomogRotate3D(toRad(orientation[2]), mgl.Vec3{0.0, 0.0, view.rotation[2]})))
view.renderRings(true)
})
}
func (view *OrientationView) renderRings(front bool) {
foreground := func(color [4]float32) [4]float32 {
if !front {
return [4]float32{0.0, 0.0, 0.0, 0.0}
}
return color
}
background := func(color [4]float32) [4]float32 {
if front {
return [4]float32{0.0, 0.0, 0.0, 0.0}
}
return color
}
// draw Z-rotation ring
view.renderRing(view.zRingVerticesStart, view.vertices,
foreground([4]float32{0.0, 0.0, 1.0, 1.0}), background([4]float32{0.0, 0.0, 0.8, 0.7}))
// draw Y-rotation ring
view.renderRing(view.yRingVerticesStart, view.zRingVerticesStart,
foreground([4]float32{0.0, 1.0, 0.0, 1.0}), background([4]float32{0.0, 0.8, 0.0, 0.7}))
// draw X-rotation ring
view.renderRing(view.xRingVerticesStart, view.yRingVerticesStart,
foreground([4]float32{1.0, 0.0, 0.0, 1.0}), background([4]float32{0.8, 0.0, 0.0, 0.7}))
}
func (view *OrientationView) renderRing(start, end int, foregroundColor, backgroundColor [4]float32) {
gl := view.context.OpenGL
modelMatrix := mgl.Ident4().Mul4(view.baseOrientation)
view.foregroundColorUniform.Set(gl, &foregroundColor)
view.backgroundColorUniform.Set(gl, &backgroundColor)
view.modelMatrixUniform.Set(gl, &modelMatrix)
gl.DrawArrays(opengl.LINES, int32(start)/3, int32(end-start)/3)
}
func (view *OrientationView) renderArrow(rotation mgl.Mat4) {
gl := view.context.OpenGL
modelMatrix := mgl.Ident4().Mul4(view.baseOrientation).Mul4(rotation)
view.foregroundColorUniform.Set(gl, &[4]float32{0.0, 0.0, 1.0, 1.0})
view.backgroundColorUniform.Set(gl, &[4]float32{0.0, 0.0, 0.6, 1.0})
view.modelMatrixUniform.Set(gl, &modelMatrix)
gl.DrawArrays(opengl.LINES, 4, 2)
modelMatrix = mgl.Ident4().Mul4(view.baseOrientation).Mul4(rotation)
view.foregroundColorUniform.Set(gl, &[4]float32{0.0, 1.0, 0.0, 1.0})
view.backgroundColorUniform.Set(gl, &[4]float32{0.0, 0.6, 0.0, 1.0})
view.modelMatrixUniform.Set(gl, &modelMatrix)
gl.DrawArrays(opengl.LINES, 2, 2)
modelMatrix = mgl.Ident4().Mul4(view.baseOrientation).Mul4(rotation)
view.foregroundColorUniform.Set(gl, &[4]float32{1.0, 0.0, 0.0, 1.0})
view.backgroundColorUniform.Set(gl, &[4]float32{0.6, 0.0, 0.0, 1.0})
view.modelMatrixUniform.Set(gl, &modelMatrix)
gl.DrawArrays(opengl.LINES, 0, 2)
}
+34
View File
@@ -0,0 +1,34 @@
package render
import (
"github.com/inkyblackness/imgui-go/v3"
"github.com/inkyblackness/hacked/editor/graphics"
"github.com/inkyblackness/hacked/ss1/resource"
"github.com/inkyblackness/hacked/ui/gui"
)
const (
// BitmapTextureTypeResource specifies a bitmap texture directly from resources.
BitmapTextureTypeResource = 0x00
// BitmapTextureTypeFrame specifies a bitmap texture from the frame cache.
BitmapTextureTypeFrame = 0x01
)
// TextureIDForBitmapTexture returns a texture ID that identifies a bitmap texture from resources.
func TextureIDForBitmapTexture(key resource.Key) imgui.TextureID {
id := imgui.TextureID(gui.ImageTypeBitmapTexture) << 56
id |= imgui.TextureID(BitmapTextureTypeResource) << 48
id |= imgui.TextureID(key.Lang) << 32
id |= imgui.TextureID(key.ID) << 16
id |= imgui.TextureID(key.Index & 0xFFFF)
return id
}
// TextureIDForBitmapFrame returns a texture ID that identifies a bitmap texture from frame cache.
func TextureIDForBitmapFrame(key graphics.FrameCacheKey) imgui.TextureID {
id := imgui.TextureID(gui.ImageTypeBitmapTexture) << 56
id |= imgui.TextureID(BitmapTextureTypeFrame) << 48
id |= imgui.TextureID(key)
return id
}
@@ -0,0 +1,40 @@
package render
import (
"math"
"github.com/inkyblackness/imgui-go/v3"
"github.com/inkyblackness/hacked/editor/graphics"
"github.com/inkyblackness/hacked/ss1/resource"
)
// TextureImage renders an image centered and fitted within the given size.
func TextureImage(label string, cache *graphics.TextureCache, key resource.Key, size imgui.Vec2) {
textureID := TextureIDForBitmapTexture(key)
imgui.PushStyleColor(imgui.StyleColorChildBg, imgui.Vec4{X: 0, Y: 0, Z: 0, W: 1})
imgui.PushStyleVarVec2(imgui.StyleVarWindowPadding, imgui.Vec2{X: 0, Y: 0})
if imgui.BeginChildV(label, size, false,
imgui.WindowFlagsNoNav|imgui.WindowFlagsNoInputs|imgui.WindowFlagsNoScrollWithMouse|
imgui.WindowFlagsNoScrollbar) {
texture, err := cache.Texture(key)
if err == nil {
var uv imgui.Vec2
uv.X, uv.Y = texture.UV()
width, height := texture.Size()
scaleFactor := float32(math.Min(float64(size.X/width), float64(size.Y/height)))
imageSize := imgui.Vec2{X: width * scaleFactor, Y: height * scaleFactor}
bufferSize := imgui.Vec2{X: (size.X - imageSize.X) / 2, Y: (size.Y - imageSize.Y) / 2}
imgui.SetCursorPos(bufferSize)
imgui.ImageV(textureID, imageSize, imgui.Vec2{}, uv,
imgui.Vec4{X: 1, Y: 1, Z: 1, W: 1}, imgui.Vec4{X: 0, Y: 0, Z: 0, W: 0})
}
}
imgui.EndChild()
imgui.PopStyleVar()
imgui.PopStyleColor()
}
@@ -0,0 +1,88 @@
package render
import (
"unsafe"
"github.com/inkyblackness/hacked/ui/opengl"
)
// TextureRenderer is a renderer within which something can be rendered onto a texture.
// This texture can then be used to be displayed.
type TextureRenderer struct {
gl opengl.OpenGL
framebuffer uint32
texture uint32
width int32
height int32
}
// NewTextureRenderer returns a new instance.
func NewTextureRenderer(gl opengl.OpenGL) *TextureRenderer {
renderer := &TextureRenderer{
gl: gl,
framebuffer: gl.GenFramebuffers(1)[0],
texture: gl.GenTextures(1)[0],
width: 200,
height: 200,
}
gl.BindTexture(opengl.TEXTURE_2D, renderer.texture)
gl.TexParameteri(opengl.TEXTURE_2D, opengl.TEXTURE_MAG_FILTER, opengl.NEAREST)
gl.TexParameteri(opengl.TEXTURE_2D, opengl.TEXTURE_MIN_FILTER, opengl.NEAREST)
offset := unsafe.Pointer(uintptr(0)) // nolint: govet
gl.TexImage2D(opengl.TEXTURE_2D, 0, opengl.RGBA, renderer.width, renderer.height, 0, opengl.RGBA, opengl.UNSIGNED_BYTE, offset)
// gl.GenerateMipmap(opengl.TEXTURE_2D)
gl.BindTexture(opengl.TEXTURE_2D, 0)
renderer.onFramebuffer(func() {
gl.BindTexture(opengl.TEXTURE_2D, renderer.texture)
gl.FramebufferTexture(opengl.FRAMEBUFFER, opengl.COLOR_ATTACHMENT0, renderer.texture, 0)
gl.DrawBuffers([]uint32{opengl.COLOR_ATTACHMENT0})
gl.BindTexture(opengl.TEXTURE_2D, 0)
// result := gl.CheckFramebufferStatus(opengl.FRAMEBUFFER)
// fmt.Printf("status: 0x%04X\n", result)
// result == FRAMEBUFFER_COMPLETE == 0x8CD5
})
return renderer
}
// Dispose cleans up resources.
func (renderer *TextureRenderer) Dispose() {
gl := renderer.gl
gl.DeleteFramebuffers([]uint32{renderer.framebuffer})
gl.DeleteTextures([]uint32{renderer.texture})
}
// Handle returns the texture handle.
func (renderer *TextureRenderer) Handle() uint32 {
return renderer.texture
}
// Size returns the dimensions of the texture, in pixels.
func (renderer *TextureRenderer) Size() (width, height float32) {
return float32(renderer.width), float32(renderer.height)
}
// Render calls the nested function. All drawing commands within this function will end up in the texture.
func (renderer *TextureRenderer) Render(nested func()) {
gl := renderer.gl
renderer.onFramebuffer(func() {
gl.Viewport(0, 0, renderer.width, renderer.height)
gl.ClearColor(0.0, 0.0, 0.0, 0.0)
gl.Clear(opengl.COLOR_BUFFER_BIT | opengl.DEPTH_BUFFER_BIT)
nested()
})
}
func (renderer *TextureRenderer) onFramebuffer(nested func()) {
gl := renderer.gl
gl.BindFramebuffer(opengl.FRAMEBUFFER, renderer.framebuffer)
nested()
gl.BindFramebuffer(opengl.FRAMEBUFFER, 0)
}
@@ -0,0 +1,44 @@
package render
import (
"fmt"
"github.com/inkyblackness/imgui-go/v3"
"github.com/inkyblackness/hacked/editor/graphics"
"github.com/inkyblackness/hacked/ss1/resource"
)
// TextureSelector renders a horizontal list of game textures, with selection capability.
func TextureSelector(label string, width float32, guiScale float32,
count int, selectedIndex int, cache *graphics.TextureCache, keyResolver func(int) resource.Key,
tooltipText func(int) string,
changeCallback func(int)) {
if imgui.BeginChildV(label, imgui.Vec2{X: width * guiScale, Y: 100 * guiScale}, true,
imgui.WindowFlagsHorizontalScrollbar|imgui.WindowFlagsNoScrollWithMouse) {
for i := 0; i < count; i++ {
key := keyResolver(i)
imgui.PushStyleVarVec2(imgui.StyleVarWindowPadding, imgui.Vec2{X: 0, Y: 0})
if imgui.BeginChildV(fmt.Sprintf("%3d", i), imgui.Vec2{X: 80 * guiScale, Y: 64 * guiScale}, false,
imgui.WindowFlagsNoNav|imgui.WindowFlagsNoScrollWithMouse) {
imgui.BeginGroup()
if imgui.SelectableV("", selectedIndex == i, 0, imgui.Vec2{X: 0, Y: 64 * guiScale}) {
changeCallback(i)
}
imgui.SameLine()
TextureImage(fmt.Sprintf("%3d", i), cache, key, imgui.Vec2{X: 64 * guiScale, Y: 64 * guiScale})
imgui.EndGroup()
if imgui.IsItemHovered() {
text := tooltipText(i)
if len(text) > 0 {
imgui.SetTooltip(text)
}
}
}
imgui.EndChild()
imgui.PopStyleVar()
imgui.SameLine()
}
}
imgui.EndChild()
}