Add hello_bs example

This commit is contained in:
ABelliqueux 2021-07-21 14:57:00 +02:00
parent 80a8990d0e
commit e9bfca654d
12 changed files with 447 additions and 3 deletions

12
hello_bs/Makefile Normal file
View File

@ -0,0 +1,12 @@
.PHONY: all cleansub
all:
mkpsxiso -y ./isoconfig.xml
cleansub:
$(MAKE) clean
rm -f hello_bs.cue hello_bs.bin
TARGET = hello_bs
SRCS = hello_bs.c \
include ../common.mk

58
hello_bs/README.md Normal file
View File

@ -0,0 +1,58 @@
# Loading a BS still image
You need [mkpsxiso](https://github.com/Lameguy64/mkpsxiso) in your $PATH to generate a PSX disk image.
## Compile
```bash
make all
```
## Clean directory
```bash
make cleansub
```
## Converting a still image to BS
`MC32` can convert these formats to BS : TIM, RGB, YUV.
### Image > TIM with img2tim
Convert your image to a 24bpp TIM with [`img2tim`](https://github.com/Lameguy64/img2tim):
```bash
img2tim -bpp 24 -o bs.tim bs.png
```
Then use `MC32` as instructed below.
### Image > RGB ppm with imagemagick
You can convert any image to PPM, then change the file's extension to .rgb, and convert it with MC32.
```bash
mogrify -format ppm image.xxx
```
### TIM/RGB > BS conversion
Use the [`MC32` tool](http://psx.arthus.net/tools/pimp-psx.zip) conversion tool to import the image, specifying the right dimensions, and convert to `bs` with those settings :
**Note that a BS image must have a width and height that is a multiple of 16**
```
Input: RGB, Output: bs
MDEC version : 2
Custom: Size in sectors or (2048 * sector number) bytes, Variable frame size
```
![MC32 bs conversion](https://wiki.arthus.net/assets/mc32-bs-conv.png)
## Sources & Refs
img2tim : https://github.com/Lameguy64/img2tim
MC32 : http://psx.arthus.net/tools/pimp-psx.zip
mdecnote : http://psx.arthus.net/sdk/Psy-Q/DOCS/TECHNOTE/mdecnote.pdf

BIN
hello_bs/bs/bace.bs Normal file

Binary file not shown.

BIN
hello_bs/bs/bace.tim Normal file

Binary file not shown.

153
hello_bs/hello_bs.c Normal file
View File

@ -0,0 +1,153 @@
// Load a BS file from CD, decompress and display it.
// Schnappy 07-2021
// based on Lameguy64's tutorial : http://lameguy64.net/svn/pstutorials/chapter1/1-display.html
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#include <libapi.h>
// CD library
#include <libcd.h>
// CODEC library
#include <libpress.h>
#include <malloc.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320 // Screen width
#define SCREENYRES 240 + (VMODE << 4) // Screen height : If VMODE is 0 = 240, if VMODE is 1 = 256
#define CENTERX SCREENXRES/2 // Center of screen on x
#define CENTERY SCREENYRES/2 // Center of screen on y
#define MARGINX 8 // margins for text display
#define MARGINY 16
#define FONTSIZE 8 * 7 // Text Field Height
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
short db = 0; // index of which buffer is used, values 0, 1
// CD specifics
#define CD_SECTOR_SIZE 2048
// Converting bytes to sectors SECTOR_SIZE is defined in words, aka int
#define BtoS(len) ( ( len + CD_SECTOR_SIZE - 1 ) / CD_SECTOR_SIZE )
// Name of file to load
static char * loadFile;
// libcd's CD file structure contains size, location and filename
CdlFILE filePos = {0};
//~ struct EXEC * exeStruct;
// Define start address of allocated memory
// Let's use an array so we don't have to worry about using a memory segment that's already in use.
static unsigned char ramAddr[0x40000]; // https://discord.com/channels/642647820683444236/663664210525290507/864936962199781387
// We could also set a memory address manually, but we have to make sure this won't get in the way of other routines.
// void * ramAddr = (void *)0x80030D40;
// Load data to this buffer
u_long * dataBuffer;
// Those are not strictly needed, but we'll use them to see the commands results.
// They could be replaced by a 0 in the various functions they're used with.
u_char CtrlResult[8];
// Value returned by CDread() - 1 is good, 0 is bad
int CDreadOK = 0;
// Value returned by CDsync() - Returns remaining sectors to load. 0 is good.
int CDreadResult = 0;
// BS decompression
// Store size of uncompressed data
long bsBufferSize;
// Allocated memory address
void * bsWorkBuffer;
// Define image draw area
RECT bsDrawArea = { 0, 0, 16, SCREENYRES};
// Used to store a 16x240 image strip
u_long bsStrip[16*240];
void init(void)
{
ResetGraph(0); // Initialize drawing engine with a complete reset (0)
SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES); // Set display area for both &disp[0] and &disp[1]
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES); // &disp[0] is on top of &disp[1]
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES); // Set draw for both &draw[0] and &draw[1]
SetDefDrawEnv(&draw[1], 0, 0 , SCREENXRES, SCREENYRES); // &draw[0] is below &draw[1]
// Set video mode
if (VMODE){ SetVideoMode(MODE_PAL);}
SetDispMask(1); // Display on screen
setRGB0(&draw[0], 155, 0, 150); // set color for first draw area
setRGB0(&draw[1], 155, 0, 150); // set color for second draw area
draw[0].isbg = 0; // set mask for draw areas. 1 means repainting the area with the RGB color each frame
draw[1].isbg = 0;
PutDispEnv(&disp[db]); // set the disp and draw environnments
PutDrawEnv(&draw[db]);
FntLoad(960, 0); // Load font to vram at 960,0(+128)
FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 ); // FntOpen(x, y, width, height, black_bg, max. nbr. chars
}
void display(void)
{
DrawSync(0); // Wait for all drawing to terminate
VSync(0); // Wait for the next vertical blank
PutDispEnv(&disp[db]); // set alternate disp and draw environnments
PutDrawEnv(&draw[db]);
db = !db; // flip db value (0 or 1)
}
int main(void)
{
// Init display
init();
// Init CD system
CdInit();
// Init heap
InitHeap((u_long *)ramAddr, sizeof(ramAddr));
// If the other method was chosen at l.39
// InitHeap((void *)0x80030D40, 0x40000);
// Set name of file to load
loadFile = "\\BACE.BS;1";
// Get file position from filename
CdSearchFile( &filePos, loadFile);
// Allocate memory
dataBuffer = malloc( BtoS(filePos.size) * CD_SECTOR_SIZE );
// Issue CdlSetloc CDROM command : Set the seek target position
// Beware of a misnomed 'sector' member in the CdlLOC struct that should really be named 'frame'.
// https://discord.com/channels/642647820683444236/663664210525290507/864912470996942910
CdControl(CdlSetloc, (u_char *)&filePos.pos, CtrlResult);
// Read data and load it to dataBuffer
CDreadOK = CdRead( (int)BtoS(filePos.size), (u_long *)dataBuffer, CdlModeSpeed );
// Wait for operation to complete
CDreadResult = CdReadSync(0, 0);
// Image Decompression
// Initialize image processing subsystem
DecDCTReset(0);
// Find the needed buffer size
bsBufferSize = DecDCTBufSize(dataBuffer);
// Allocate buffer size at &bsWorkBuffer
bsWorkBuffer = malloc( bsBufferSize );
// Decode Huffman (also called VLC: variable length coding ) compressed image
DecDCTvlc( dataBuffer, (u_long *) bsWorkBuffer );
// Send decoded data to MDEC for RLE decoding.
DecDCTin( (u_long*) bsWorkBuffer, 0);
// Fetch decoded image in 16x240 strips
for( bsDrawArea.x = 0; bsDrawArea.x < SCREENXRES; bsDrawArea.x += 16 ){
// Request decoded data from MDEC
// Request 16 * 240 pixel high lines.
// But size is in long words (4B), so divide by 2 to get words (2B) ?
DecDCTout( bsStrip, (16*SCREENYRES)/2);
// Wait for transfer to complete
DecDCToutSync(0);
// Load image data to fb
LoadImage( &bsDrawArea, bsStrip );
}
free( bsWorkBuffer );
while (1) // infinite loop
{
// Copy BS image to the other buffer
MoveImage2(&disp[db].disp, 0, disp[!db].disp.y );
DrawSync(0);
FntPrint("Hello BS! \n");
// Print filesize in bytes/sectors
FntPrint("Bs Size: %dB sectors: %d\n", filePos.size, BtoS(filePos.size));
// Print heap and buffer addresses
FntPrint("Heap: %x - Buf: %x\n", ramAddr, dataBuffer);
FntPrint("bsWork: %x\nbsBufSize: %dB\n", bsWorkBuffer, bsBufferSize);
FntFlush(-1); // Draw print stream
display(); // Execute display()
}
return 0;
}

100
hello_bs/isoconfig.xml Normal file
View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- MKPSXISO example XML script -->
<!-- <iso_project>
Starts an ISO image project to build. Multiple <iso_project> elements may be
specified within the same xml script which useful for multi-disc projects.
<iso_project> elements must contain at least one <track> element.
Attributes:
image_name - File name of the ISO image file to generate.
cue_sheet - Optional, file name of the cue sheet for the image file
(required if more than one track is specified).
-->
<iso_project image_name="hello_bs.bin" cue_sheet="hello_bs.cue">
<!-- <track>
Specifies a track to the ISO project. This example element creates a data
track for storing data files and CD-XA/STR streams.
Only one data track is allowed and data tracks must only be specified as the
first track in the ISO image and cannot be specified after an audio track.
Attributes:
type - Track type (either data or audio).
source - For audio tracks only, specifies the file name of a wav audio
file to use for the audio track.
-->
<track type="data">
<!-- <identifiers>
Optional, Specifies the identifier strings to use for the data track.
Attributes:
system - Optional, specifies the system identifier (PLAYSTATION if unspecified).
application - Optional, specifies the application identifier (PLAYSTATION if unspecified).
volume - Optional, specifies the volume identifier.
volume_set - Optional, specifies the volume set identifier.
publisher - Optional, specifies the publisher identifier.
data_preparer - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO
will fill it with lengthy text telling that the image file was generated
using MKPSXISO.
-->
<identifiers
system ="PLAYSTATION"
application ="PLAYSTATION"
volume ="HELOCD"
volume_set ="HELOCD"
publisher ="SCHNAPPY"
data_preparer ="MKPSXISO"
/>
<!-- <license>
Optional, specifies the license file to use, the format of the license file must be in
raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\cdgen\LCNSFILE.
License data is not included within the MKPSXISO program to avoid possible legal problems
in the open source environment... Better be safe than sorry.
Attributes:
file - Specifies the license file to inject into the ISO image.
-->
<!--
<license file="LICENSEA.DAT"/>
-->
<!-- <directory_tree>
Specifies and contains the directory structure for the data track.
Attributes:
None.
-->
<directory_tree>
<!-- <file>
Specifies a file in the directory tree.
Attributes:
name - File name to use in the directory tree (can be used for renaming).
type - Optional, type of file (data for regular files and is the default, xa for
XA audio and str for MDEC video).
source - File name of the source file.
-->
<!-- Stores system.txt as system.cnf -->
<file name="system.cnf" type="data" source="system.cnf"/>
<file name="SCES_313.37" type="data" source="hello_bs.ps-exe"/>
<file name="BACE.BS" type="data" source="bs/bace.bs"/>
<dummy sectors="1024"/>
<!-- <dir>
Specifies a directory in the directory tree. <file> and <dir> elements inside the element
will be inside the specified directory.
-->
</directory_tree>
</track>
</iso_project>

4
hello_bs/system.cnf Normal file
View File

@ -0,0 +1,4 @@
BOOT=cdrom:\SCES_313.37;1
TCB=4
EVENT=10
STACK=801FFFF0

View File

@ -29,7 +29,7 @@ short db = 0; // index of which buffer is used, values 0, 1
// Converting bytes to sectors SECTOR_SIZE is defined in words, aka int // Converting bytes to sectors SECTOR_SIZE is defined in words, aka int
#define BtoS(len) ( ( len + CD_SECTOR_SIZE - 1 ) / CD_SECTOR_SIZE ) #define BtoS(len) ( ( len + CD_SECTOR_SIZE - 1 ) / CD_SECTOR_SIZE )
// Name of file to load // Name of file to load
static char * exeFile; static char * loadFile;
// libcd's CD file structure contains size, location and filename // libcd's CD file structure contains size, location and filename
CdlFILE filePos = {0}; CdlFILE filePos = {0};
//~ struct EXEC * exeStruct; //~ struct EXEC * exeStruct;
@ -86,9 +86,9 @@ int main(void)
// If the other method was chosen at l.39 // If the other method was chosen at l.39
// InitHeap((void *)0x80030D40, 0x40000); // InitHeap((void *)0x80030D40, 0x40000);
// Set name of file to load // Set name of file to load
exeFile = "\\HELO.DAT;1"; loadFile = "\\HELO.DAT;1";
// Get file position from filename // Get file position from filename
CdSearchFile( &filePos, exeFile); CdSearchFile( &filePos, loadFile);
// Allocate memory // Allocate memory
dataBuffer = malloc( BtoS(filePos.size) * CD_SECTOR_SIZE ); dataBuffer = malloc( BtoS(filePos.size) * CD_SECTOR_SIZE );
// Issue CdlSetloc CDROM command : Set the seek target position // Issue CdlSetloc CDROM command : Set the seek target position

12
hello_str/Makefile Normal file
View File

@ -0,0 +1,12 @@
.PHONY: all cleansub
all:
mkpsxiso -y ./isoconfig.xml
cleansub:
$(MAKE) clean
rm -f hello_str.cue hello_str.bin
TARGET = hello_str
SRCS = hello_str.c \
include ../common.mk

101
hello_str/isoconfig.xml Normal file
View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- MKPSXISO example XML script -->
<!-- <iso_project>
Starts an ISO image project to build. Multiple <iso_project> elements may be
specified within the same xml script which useful for multi-disc projects.
<iso_project> elements must contain at least one <track> element.
Attributes:
image_name - File name of the ISO image file to generate.
cue_sheet - Optional, file name of the cue sheet for the image file
(required if more than one track is specified).
-->
<iso_project image_name="hello_str.bin" cue_sheet="hello_str.cue">
<!-- <track>
Specifies a track to the ISO project. This example element creates a data
track for storing data files and CD-XA/STR streams.
Only one data track is allowed and data tracks must only be specified as the
first track in the ISO image and cannot be specified after an audio track.
Attributes:
type - Track type (either data or audio).
source - For audio tracks only, specifies the file name of a wav audio
file to use for the audio track.
-->
<track type="data">
<!-- <identifiers>
Optional, Specifies the identifier strings to use for the data track.
Attributes:
system - Optional, specifies the system identifier (PLAYSTATION if unspecified).
application - Optional, specifies the application identifier (PLAYSTATION if unspecified).
volume - Optional, specifies the volume identifier.
volume_set - Optional, specifies the volume set identifier.
publisher - Optional, specifies the publisher identifier.
data_preparer - Optional, specifies the data preparer identifier. If unspecified, MKPSXISO
will fill it with lengthy text telling that the image file was generated
using MKPSXISO.
-->
<identifiers
system ="PLAYSTATION"
application ="PLAYSTATION"
volume ="HELOCD"
volume_set ="HELOCD"
publisher ="SCHNAPPY"
data_preparer ="MKPSXISO"
/>
<!-- <license>
Optional, specifies the license file to use, the format of the license file must be in
raw 2336 byte sector format, like the ones included with the PsyQ SDK in psyq\cdgen\LCNSFILE.
License data is not included within the MKPSXISO program to avoid possible legal problems
in the open source environment... Better be safe than sorry.
Attributes:
file - Specifies the license file to inject into the ISO image.
-->
<!--
<license file="LICENSEA.DAT"/>
-->
<!-- <directory_tree>
Specifies and contains the directory structure for the data track.
Attributes:
None.
-->
<directory_tree>
<!-- <file>
Specifies a file in the directory tree.
Attributes:
name - File name to use in the directory tree (can be used for renaming).
type - Optional, type of file (data for regular files and is the default, xa for
XA audio and str for MDEC video).
source - File name of the source file.
-->
<!-- Stores system.txt as system.cnf -->
<file name="system.cnf" type="data" source="system.cnf"/>
<file name="SCES_313.37" type="data" source="hello_str.ps-exe"/>
<file name="COPY.STR" type="str" source="str/copyings.str"/>
<dummy sectors="1024"/>
<!-- <dir>
Specifies a directory in the directory tree. <file> and <dir> elements inside the element
will be inside the specified directory.
-->
</directory_tree>
</track>
</iso_project>

BIN
hello_str/str/copyings.str Normal file

Binary file not shown.

4
hello_str/system.cnf Normal file
View File

@ -0,0 +1,4 @@
BOOT=cdrom:\SCES_313.37;1
TCB=4
EVENT=10
STACK=801FFFF0