Skip to content

Commit

Permalink
Convert colors in C
Browse files Browse the repository at this point in the history
  • Loading branch information
sergystepanov committed Sep 22, 2023
1 parent 8dd9e9c commit 85cef0d
Show file tree
Hide file tree
Showing 8 changed files with 513 additions and 486 deletions.
142 changes: 142 additions & 0 deletions pkg/worker/caged/libretro/image/canvas.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include "canvas.h"

__inline int rot_x(int t, int x, int y, int w, int h) {
switch (t) {
case 1:
return r90_x(x,y,w,h);
break;
case 2:
return r180_x(x,y,w,h);
break;
case 3:
return r270_x(x,y,w,h);
break;
case 4:
return fy180_x(x,y,w,h);
break;
}
return x;
}

__inline int rot_y(int t, int x, int y, int w, int h) {
switch (t) {
case 1:
return r90_y(x,y,w,h);
break;
case 2:
return r180_y(x,y,w,h);
break;
case 3:
return r270_y(x,y,w,h);
break;
case 4:
return fy180_y(x,y,w,h);
break;
}
return y;
}


void RGBA(int pix, void *destination, void *source, int yy, int yn, int xw, int xh, int dw, int pad, int rot) {
switch (pix) {
case BIT_SHORT5551:
break;
case BIT_INT_8888REV:
if (rot == 0) {
i8888(destination, source, yy, yn, xw, pad);
} else {
i8888r(destination, source, yy, yn, xw, xh, dw, pad, rot);
}
break;
case BIT_SHORT565:
if (rot == 0) {
i565(destination, source, yy, yn, xw, pad);
} else {
i565r(destination, source, yy, yn, xw, xh, dw, pad, rot);
}
break;
}
}

void i565(void *destination, void *source, int yy, int yn, int xw, int pad) {
uint8_t *src = source; // must be in bytes because of possible padding in bytes
uint32_t *dst = destination;

int y, x;
uint32_t px;

for (y = yy; y < yn; ++y) {
for (x = 0; x < xw; ++x) {
px = *(uint16_t *)src;
src += 2;
*dst++ = _565(px);
}
src += pad;
}
}

void i565r(void *destination, void *source, int yy, int yn, int xw, int xh, int dw, int pad, int rot) {
uint8_t *src = source;
uint32_t *dst = destination;

uint32_t px;

int x, y, dx, dy;

for (y = yy; y < yn; ++y) {
for (x = 0; x < xw; ++x) {
px = *(uint16_t *)src;
src += 2;

dx = rot_x(rot, x, y, xw, xh);
dy = rot_y(rot, x, y, xw, xh);

dst[dx+dy*dw] = _565(px);
}
src += pad;
}
}

void i8888r(void *destination, void *source, int yy, int yn, int xw, int xh, int dw, int pad, int rot) {
uint8_t *src = source;
uint32_t *dst = destination;

int y, x;
uint32_t px;

int dx, dy;

for (y = yy; y < yn; ++y) {
for (x = 0; x < xw; ++x) {
px = *(uint32_t *)src;

dx = rot_x(rot, x, y, xw, xh);
dy = rot_y(rot, x, y, xw, xh);

dst[dx+dy*dw] = _8888rev(px);
src += 4;
}
src += pad;
}
}

void i8888(void *destination, void *source, int yy, int yn, int xw, int pad) {
uint8_t *src = source; // must be in bytes because of possible padding in bytes
uint32_t *dst = destination;

int y, x;
uint32_t px;

for (y = yy; y < yn; ++y) {
for (x = 0; x < xw; ++x) {
px = *(uint32_t *)src;
src += 4;
*dst++ = _8888rev(px);
}
src += pad;
}
}

uint32_t px8888rev(uint32_t px) {
return _8888rev(px);
}
120 changes: 51 additions & 69 deletions pkg/worker/caged/libretro/image/canvas.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ package image

import (
"image"
"math/bits"
"sync"
"unsafe"

"golang.org/x/image/draw"
)

/*
#cgo CFLAGS: -Wall
#include "canvas.h"
*/
import "C"

// Canvas is a stateful drawing surface, i.e. image.RGBA
type Canvas struct {
enabled bool
Expand All @@ -30,6 +37,35 @@ const (
BitFormatShort565 // BIT_FORMAT_SHORT_5_6_5 has 5 bits R, 6 bits G, 5 bits
)

const (
ScaleNot = iota // skips image interpolation
ScaleNearestNeighbour // nearest neighbour interpolation
ScaleBilinear // bilinear interpolation
)

func Resize(scaleType int, src *image.RGBA, out *image.RGBA) {
// !to do set it once instead switching on each iteration
switch scaleType {
case ScaleBilinear:
draw.ApproxBiLinear.Scale(out, out.Bounds(), src, src.Bounds(), draw.Src, nil)
case ScaleNot:
fallthrough
case ScaleNearestNeighbour:
fallthrough
default:
draw.NearestNeighbor.Scale(out, out.Bounds(), src, src.Bounds(), draw.Src, nil)
}
}

type Rotation uint

const (
A90 Rotation = iota + 1
A180
A270
F180 // F180 is flipped Y
)

func NewCanvas(w, h, size int) *Canvas {
return &Canvas{
enabled: true,
Expand Down Expand Up @@ -66,17 +102,17 @@ func (c *Canvas) Put(i *Frame) {
func (c *Canvas) Clear() { c.wg = sync.WaitGroup{} }
func (c *Canvas) SetEnabled(enabled bool) { c.enabled = enabled }

func (c *Canvas) Draw(encoding uint32, rot *Rotate, w, h, packedW, bpp int, data []byte, th int) *Frame {
func (c *Canvas) Draw(encoding uint32, rot Rotation, w, h, packedW, bpp int, data []byte, th int) *Frame {
dst := c.Get(w, h)
if th == 0 {
frame(encoding, dst, data, 0, h, h, w, packedW, bpp, rot)
frame(encoding, dst, data, 0, h, w, h, packedW, bpp, rot)
} else {
hn := h / th
c.wg.Add(th)
for i := 0; i < th; i++ {
xx := hn * i
go func() {
frame(encoding, dst, data, xx, hn, h, w, packedW, bpp, rot)
frame(encoding, dst, data, xx, hn, w, h, packedW, bpp, rot)
c.wg.Done()
}()
}
Expand All @@ -100,77 +136,23 @@ func (c *Canvas) Draw(encoding uint32, rot *Rotate, w, h, packedW, bpp int, data
return dst
}

func frame(encoding uint32, dst *Frame, data []byte, yy int, hn int, h int, w int, pwb int, bpp int, rot *Rotate) {
func frame(encoding uint32, dst *Frame, data []byte, yy int, hn int, w int, h int, pwb int, bpp int, rot Rotation) {
sPtr := unsafe.Pointer(&data[yy*pwb])
dPtr := unsafe.Pointer(&dst.Pix[yy*dst.Stride])
// some cores can zero-right-pad rows to the packed width value
pad := pwb - w*bpp
yn := yy + hn

if rot == nil {
// LE, BE might not work
switch encoding {
case BitFormatShort565:
for y := yy; y < yn; y++ {
for x := 0; x < w; x++ {
i565((*uint32)(dPtr), uint32(*(*uint16)(sPtr)))
sPtr = unsafe.Add(sPtr, uintptr(bpp))
dPtr = unsafe.Add(dPtr, uintptr(4))
}
if pad > 0 {
sPtr = unsafe.Add(sPtr, uintptr(pad))
}
}
case BitFormatInt8888Rev:
for y := yy; y < yn; y++ {
for x := 0; x < w; x++ {
ix8888((*uint32)(dPtr), *(*uint32)(sPtr))
sPtr = unsafe.Add(sPtr, uintptr(bpp))
dPtr = unsafe.Add(dPtr, uintptr(4))
}
if pad > 0 {
sPtr = unsafe.Add(sPtr, uintptr(pad))
}
}
}
} else {
switch encoding {
case BitFormatShort565:
for y := yy; y < yn; y++ {
for x, k := 0, 0; x < w; x++ {
dx, dy := rot.Call(x, y, w, h)
k = dx<<2 + dy*dst.Stride
dPtr = unsafe.Pointer(&dst.Pix[k])
i565((*uint32)(dPtr), uint32(*(*uint16)(sPtr)))
sPtr = unsafe.Add(sPtr, uintptr(bpp))
}
if pad > 0 {
sPtr = unsafe.Add(sPtr, uintptr(pad))
}
}
case BitFormatInt8888Rev:
for y := yy; y < yn; y++ {
for x, k := 0, 0; x < w; x++ {
dx, dy := rot.Call(x, y, w, h)
k = dx<<2 + dy*dst.Stride
dPtr = unsafe.Pointer(&dst.Pix[k])
ix8888((*uint32)(dPtr), *(*uint32)(sPtr))
sPtr = unsafe.Add(sPtr, uintptr(bpp))
}
if pad > 0 {
sPtr = unsafe.Add(sPtr, uintptr(pad))
}
}
}
if pad < 0 {
pad = 0
}
if rot != 0 {
dPtr = unsafe.Pointer(&dst.Pix[0])
}
C.RGBA(C.int(encoding), dPtr, sPtr, C.int(yy), C.int(yy+hn), C.int(w), C.int(h), C.int(dst.Stride>>2), C.int(pad), C.int(rot))
}

func i565(dst *uint32, px uint32) {
*dst = (px >> 8 & 0xf8) | ((px >> 3 & 0xfc) << 8) | ((px << 3 & 0xfc) << 16) // | 0xff000000
// setting the last byte to 255 allows saving RGBA images to PNG not as black squares
}
func _8888rev(px uint32) uint32 { return uint32(C.px8888rev(C.uint32_t(px))) }

func ix8888(dst *uint32, px uint32) {
//*dst = ((px >> 16) & 0xff) | (px & 0xff00) | ((px << 16) & 0xff0000) + 0xff000000
*dst = bits.ReverseBytes32(px << 8) //| 0xff000000
func rotate(t int, x int, y int, w int, h int) (int, int) {
return int(C.rot_x(C.int(t), C.int(x), C.int(y), C.int(w), C.int(h))),
int(C.rot_y(C.int(t), C.int(x), C.int(y), C.int(w), C.int(h)))
}
42 changes: 42 additions & 0 deletions pkg/worker/caged/libretro/image/canvas.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef CANVAS_H__
#define CANVAS_H__

#include <stdint.h>

#define BIT_SHORT5551 0
#define BIT_INT_8888REV 1
#define BIT_SHORT565 2

// Rotate90 is 90° CCW or 270° CW.
#define r90_x(x, y, w, h) ( y )
#define r90_y(x, y, w, h) ( (w - 1) - x )

// Rotate180 is 180° CCW.
#define r180_x(x, y, w, h) ( (w - 1) - x )
#define r180_y(x, y, w, h) ( (h - 1) - y )

// Rotate270 is 270° CCW or 90° CW.
#define r270_x(x, y, w, h) ( (h - 1) - y )
#define r270_y(x, y, w, h) ( x )

// Flip Y
#define fy180_x(x, y, w, h) ( x )
#define fy180_y(x, y, w, h) ( (h - 1) - y )

int rot_x(int t, int x, int y, int w, int h);
int rot_y(int t, int x, int y, int w, int h);

#define _565(x) ((x >> 8 & 0xf8) | ((x >> 3 & 0xfc) << 8) | ((x << 3 & 0xfc) << 16)); // | 0xff000000
#define _8888rev(px) (((px >> 16) & 0xff) | (px & 0xff00) | ((px << 16) & 0xff0000)); // | 0xff000000)


void RGBA(int pix, void *destination, void *source, int yy, int yn, int xw, int xh, int dw, int pad, int rot);

void i565(void *destination, void *source, int yy, int yn, int xw, int pad);
void i8888(void *destination, void *source, int yy, int yn, int xw, int pad);
void i565r(void *destination, void *source, int yy, int yn, int xw, int xh, int dw, int pad, int rot);
void i8888r(void *destination, void *source, int yy, int yn, int xw, int xh, int dw, int pad, int rot);

uint32_t px8888rev(uint32_t px);

#endif
Loading

0 comments on commit 85cef0d

Please sign in to comment.