2024-07-23 23:00:19 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Convert rgb to uint
|
|
|
|
func Col2Uint(r, g, b byte) uint {
|
|
|
|
return (uint(r) << 16) | (uint(g) << 8) | uint(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Convert uint to rgb (in that order)
|
|
|
|
func Uint2Col(col uint) (byte, byte, byte) {
|
|
|
|
return byte((col >> 16) & 0xFF), byte((col >> 8) & 0xFF), byte(col & 0xFF)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Color is in ARGB (alpha not used right now)
|
|
|
|
type Framebuffer struct {
|
|
|
|
Data []uint
|
|
|
|
Width uint
|
|
|
|
Height uint
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a new framebuffer for the given width and height.
|
|
|
|
func NewFramebuffer(width uint, height uint) Framebuffer {
|
|
|
|
return Framebuffer{
|
|
|
|
Data: make([]uint, width*height),
|
|
|
|
Width: width,
|
|
|
|
Height: height,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-23 23:37:02 +00:00
|
|
|
// Sure hope this gets inlined...
|
|
|
|
func (fb *Framebuffer) Set(x uint, y uint, color uint) {
|
|
|
|
fb.Data[x+y*fb.Width] = color
|
|
|
|
}
|
|
|
|
|
2024-07-24 03:01:31 +00:00
|
|
|
func (fb *Framebuffer) SetSafe(x uint, y uint, color uint) {
|
|
|
|
if x >= fb.Width || y >= fb.Height {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
fb.Data[x+y*fb.Width] = color
|
|
|
|
}
|
|
|
|
|
2024-07-23 23:00:19 +00:00
|
|
|
// Given some image data, return a string that is the ppm of it
|
|
|
|
func (fb *Framebuffer) ExportPPM() string {
|
|
|
|
var result strings.Builder
|
|
|
|
result.WriteString(fmt.Sprintf("P3\n%d %d\n255\n", fb.Width, fb.Height))
|
|
|
|
for y := range fb.Height {
|
|
|
|
for x := range fb.Width {
|
|
|
|
r, g, b := Uint2Col(fb.Data[x+y*fb.Width])
|
|
|
|
result.WriteString(fmt.Sprintf("%d %d %d\t", r, g, b))
|
|
|
|
}
|
|
|
|
result.WriteRune('\n')
|
|
|
|
}
|
|
|
|
return result.String()
|
|
|
|
}
|