Move to better file structure

This commit is contained in:
ABelliqueux 2021-07-10 13:36:57 +02:00
parent 7275cbdb02
commit c047197a89
44 changed files with 5281 additions and 317 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "thirdparty/nugget"]
path = thirdparty/nugget
url = https://github.com/pcsx-redux/nugget.git

255
Makefile
View File

@ -1,171 +1,88 @@
## Hello world
TARGET = hello_world
TYPE = ps-exe
hello_world:
$(MAKE) -C hello_world
hello_2pads:
$(MAKE) -C hello_2pads
hello_cube:
$(MAKE) -C hello_cube
hello_cubetex:
$(MAKE) -C hello_cubetex
hello_poly_fun:
$(MAKE) -C hello_poly_fun
hello_gte_opti:
$(MAKE) -C hello_gte_opti
hello_light:
$(MAKE) -C hello_light
hello_multivag:
$(MAKE) -C hello_multivag
hello_pad:
$(MAKE) -C hello_pad
hello_poly:
$(MAKE) -C hello_poly
hello_poly_ft:
$(MAKE) -C hello_poly_ft
hello_poly_gt:
$(MAKE) -C hello_poly_gt
hello_poly_gt_tw:
$(MAKE) -C hello_poly_gt_tw
hello_poly_inline:
$(MAKE) -C hello_poly_inline
hello_poly_subdiv:
$(MAKE) -C hello_poly_subdiv
hello_rsd:
$(MAKE) -C hello_rsd
hello_sio:
$(MAKE) -C hello_sio
hello_sprt:
$(MAKE) -C hello_sprt
hello_tile:
$(MAKE) -C hello_tile
hello_vag:
$(MAKE) -C hello_vag
SRCS = hello_world.c \
../common/crt0/crt0.s \
clean:
$(MAKE) -C hello_2pads clean
$(MAKE) -C hello_cube clean
$(MAKE) -C hello_cubetex clean
$(MAKE) -C hello_poly_fun clean
$(MAKE) -C hello_gte_opti clean
$(MAKE) -C hello_light clean
$(MAKE) -C hello_multivag clean
$(MAKE) -C hello_pad clean
$(MAKE) -C hello_poly clean
$(MAKE) -C hello_poly_ft clean
$(MAKE) -C hello_poly_gt clean
$(MAKE) -C hello_poly_gt_tw clean
$(MAKE) -C hello_poly_inline clean
$(MAKE) -C hello_poly_subdiv clean
$(MAKE) -C hello_rsd clean
$(MAKE) -C hello_sio clean
$(MAKE) -C hello_sprt clean
$(MAKE) -C hello_tile clean
$(MAKE) -C hello_vag clean
$(MAKE) -C hello_world clean
#~ ## Hello tile
#~ TARGET = hello_tile
#~ TYPE = ps-exe
#~ SRCS = hello_tile.c \
#~ ../common/crt0/crt0.s \
#~ ## Hello pad
#~ TARGET = hello_pad
#~ TYPE = ps-exe
#~ SRCS = hello_pad.c \
#~ ../common/crt0/crt0.s \
#~ ## Hello pad 2
#~ TARGET = hello_2pads
#~ TYPE = ps-exe
#~ SRCS = hello_2pads.c \
#~ ../common/crt0/crt0.s \
#~ ## Hello poly
#~ TARGET = hello_poly
#~ TYPE = ps-exe
#~ SRCS = hello_poly.c \
#~ ../common/crt0/crt0.s \
#~ ## Hello inline GTE
#~ TARGET = hello_poly_inline
#~ TYPE = ps-exe
#~ SRCS = hello_poly_inline.c \
#~ ../common/crt0/crt0.s \
## Hello inline GTE
#~ TARGET = hello_gte_opti
#~ TYPE = ps-exe
#~ SRCS = hello_gte_opti.c \
#~ ../common/crt0/crt0.s \
## Hello poly subdiv
#~ TARGET = hello_poly_subdiv
#~ TYPE = ps-exe
#~ SRCS = hello_poly_subdiv.c \
#~ ../common/crt0/crt0.s \
#~ ## Hello textured
#~ TARGET = hello_poly_ft
#~ TYPE = ps-exe
#~ SRCS = hello_poly_ft.c \
#~ ../common/crt0/crt0.s \
#~ TIM/bousai.tim \
#~ ## Hello shaded textured
#~ TARGET = hello_poly_gt
#~ TYPE = ps-exe
#~ SRCS = hello_poly_gt.c \
#~ ../common/crt0/crt0.s \
#~ TIM/bousai.tim \
#~ ## Hello shaded window textured
#~ TARGET = hello_poly_gt_tw
#~ TYPE = ps-exe
#~ SRCS = hello_poly_gt_tw.c \
#~ ../common/crt0/crt0.s \
#~ TIM/bousai.tim \
#~ ## Hello sprt
#~ TARGET = hello_sprt
#~ TYPE = ps-exe
#~ SRCS = hello_sprt.c \
#~ ../common/crt0/crt0.s \
#~ TIM/TIM16.tim \
#~ TIM/TIM8.tim \
#~ TIM/TIM4.tim \
#~ ## hello vag
#~ TARGET = hello_vag
#~ TYPE = ps-exe
#~ SRCS = hello_vag.c \
#~ ../common/crt0/crt0.s \
#~ VAG/hello_poly.vag \
#~ ## hello multivag
#~ TARGET = hello_multivag
#~ TYPE = ps-exe
#~ SRCS = hello_multivag.c \
#~ ../common/crt0/crt0.s \
#~ VAG/hello.vag \
#~ VAG/poly.vag \
#~ ## Poly fun !
#~ TARGET = fun_with_poly
#~ TYPE = ps-exe
#~ SRCS = fun_with_poly.c \
#~ ../common/crt0/crt0.s \
## hello cube
#~ TARGET = hello_cube
#~ TYPE = ps-exe
#~ SRCS = hello_cube.c \
#~ ../common/crt0/crt0.s \
## hello cubetex
#~ TARGET = hello_cubetex
#~ TYPE = ps-exe
#~ SRCS = hello_cubetex.c \
#~ ../common/crt0/crt0.s \
#~ TIM/cubetex.tim \
#~ ## hello light
#~ TARGET = hello_light
#~ TYPE = ps-exe
#~ SRCS = hello_light.c \
#~ ../common/crt0/crt0.s \
#~ ## Hello sio
#~ TARGET = hello_sio
#~ TYPE = ps-exe
#~ SRCS = hello_sio.c \
#~ ../common/crt0/crt0.s \
CPPFLAGS += -I../psyq/include
LDFLAGS += -L../psyq/lib
LDFLAGS += -Wl,--start-group
LDFLAGS += -lapi
LDFLAGS += -lc
LDFLAGS += -lc2
LDFLAGS += -lcard
LDFLAGS += -lcomb
LDFLAGS += -lds
LDFLAGS += -letc
LDFLAGS += -lgpu
LDFLAGS += -lgs
LDFLAGS += -lgte
LDFLAGS += -lgun
LDFLAGS += -lhmd
LDFLAGS += -lmath
LDFLAGS += -lmcrd
LDFLAGS += -lmcx
LDFLAGS += -lpad
LDFLAGS += -lpress
LDFLAGS += -lsio
LDFLAGS += -lsnd
LDFLAGS += -lspu
LDFLAGS += -ltap
LDFLAGS += -lcd
LDFLAGS += -Wl,--end-group
include ../common.mk \
all:
$(MAKE) -C hello_2pads
$(MAKE) -C hello_cube
$(MAKE) -C hello_cubetex
$(MAKE) -C hello_poly_fun
$(MAKE) -C hello_gte_opti
$(MAKE) -C hello_light
$(MAKE) -C hello_multivag
$(MAKE) -C hello_pad
$(MAKE) -C hello_poly
$(MAKE) -C hello_poly_ft
$(MAKE) -C hello_poly_gt
$(MAKE) -C hello_poly_gt_tw
$(MAKE) -C hello_poly_inline
$(MAKE) -C hello_poly_subdiv
$(MAKE) -C hello_rsd
$(MAKE) -C hello_sio
$(MAKE) -C hello_sprt
$(MAKE) -C hello_tile
$(MAKE) -C hello_vag
$(MAKE) -C hello_world
# declare phony rules
.PHONY: hello_2pads hello_cube hello_cubetex hello_poly_fun hello_gte_opti hello_light hello_multivag hello_pad hello_poly hello_poly_ft hello_poly_gt hello_poly_gt_tw hello_poly_inline hello_poly_subdiv hello_rsd hello_sio hello_sprt hello_tile hello_vag hello_world \
clean all

206
README.md
View File

@ -2,190 +2,100 @@
<p align="center">
<img height="240px" src="cube.gif" alt="3D power !">
<img height="240px" src="http://wiki.arthus.net/pico/assets/cube.gif" alt="3D power !">
<img height="240px" src="http://psx.arthus.net/homebrew/polyfun.jpg" alt="3D power !">
<img height="240px" src="http://wiki.arthus.net/pico/assets/polyfun.jpg" alt="3D power !">
<img height="240px" src="hello_gt.jpg" alt="3D power !">
<img height="240px" src="http://wiki.arthus.net/pico/assets/hello_gt.jpg" alt="3D power !">
</p>
So you want to begin developping on the original PSX but don't know where to start ?
So you want to begin developping on the original PSX but don't know where to start ?
This repo is destined to host a bunch of simple examples, each describing how to do one thing.
This repo is destined to host a bunch of simple examples, each describing how to do one thing.
The code here will be using PsyQ, the "Official" Sony SDK, but we will not be using libGS, the Extended Graphics Library for the graphic stuff...
The code here will be using **Nugget + PsyQ**, the "Official" Sony SDK but with a modern MIPS toolchain.
We will not be using libGS, the Extended Graphics Library for the graphic stuff...
Instead we'll try to devise methods to reproduce libgs functions. This will not necessarly be more efficient, but we'll learn
a lot more stuff !
a lot more stuff !
## Setting up the SDK : Modern GCC + PsyQ a.k.a Nugget+PsyQ
## Installation
For this we'll rely heavily on [grumpy-coder](https://github.com/grumpycoders/pcsx-redux)'s work with pcsx-redux and various tools, which will provide us with:
We'll keep things simple for now. If you want to read about more methods to get things up and running, see the wiki's [Installation methods](https://github.com/ABelliqueux/nolibgs_hello_worlds/wiki/Installation-methods) section.
* A way to compile the code with a modern version of GCC
* An emulator with a lot of debugging features
### Let's do it !
#### MacOS
* On MacOs, a brew installation script can be found [here.](https://github.com/grumpycoders/pcsx-redux#macos)
#### Windows 10
* Native build :
Follow the [instructions here](https://github.com/grumpycoders/pcsx-redux#windows) to build pcsx-redux or download a pre-compiled [pcsx-redux binary here](https://github.com/grumpycoders/pcsx-redux/#where).
* Win 10 + WSL2 (needs GUI support):
Install WSL2 with GUI support and [Ubuntu 20.04](https://www.microsoft.com/en-gb/p/ubuntu-2004-lts/9n6svws3rx71?activetab=pivot:overviewtab) then launch a GNU/Linux terminal, then proceed with the following instructions.
* Alternatively on Windows, if you don't care about getting/compiling pcsx-redux, you can skip steps 1, 3 and 4, get the latest precompiled toolchain from here : [http://static.grumpycoder.net/pixel/mips/](http://static.grumpycoder.net/pixel/mips/), unzip it somewhere and [add the `bin` folder to your PATH](https://stackoverflow.com/questions/44272416/how-to-add-a-folder-to-path-environment-variable-in-windows-10-with-screensho#44272417). Then go on with steps 5 and 6.
#### GNU/Linux
1. Install the needed software packages ( aka dependencies in Linux world ) :
* To be able to build PsyQ code, you only need the MIPS toolchain :
### Windows
#### MIPS toolchain setup
1. Download the MIPS toolchain here : [http://static.grumpycoder.net/pixel/mips/g++-mipsel-none-elf-10.3.0.zip](http://static.grumpycoder.net/pixel/mips/g++-mipsel-none-elf-10.3.0.zip)
2. Unzip anywhere on your hard-drive and add the `bin` folder to [your $PATH](https://stackoverflow.com/questions/44272416/how-to-add-a-folder-to-path-environment-variable-in-windows-10-with-screensho#44272417).
3. Test everything is fine by [launching a command prompt](https://www.lifewire.com/how-to-open-command-prompt-2618089) and typing `mipsel-none-elf-gcc.exe --version`. If you get a message like `mipsel-none-gnu-gcc (GCC) 10.3.0`, then it's working !
#### Nugget + PsyQ setup
1. Download the PsyQ converted libraries here : [http://psx.arthus.net/sdk/Psy-Q/psyq-4_7-converted-light.zip](http://psx.arthus.net/sdk/Psy-Q/psyq-4_7-converted-light.zip)
2. Download this repository's archive here : [REPLACEME](REPLACEME)
3. Unzip the **`main.zip`** file anywhere on your hard-drive. We'll use `C:\psxdev\` as an example
4. Unzip the `psyq-4_7-converted-light.zip` file in `C:\psxdev\psyq`. You should now have `C:\psxdev\psyq\include` and `C:\psxdev\psyq\lib`.
5. Test everything is working by [launching a command prompt](https://www.lifewire.com/how-to-open-command-prompt-2618089), change to the `C:\psxdev\` directory with the following command: `cd C:\psxdev\`, then type `make` and hit enter. By default, this should build the `hello_world` example, and you should now have a `hello_world.ps-exe` file in `C:\psxdev\hello_world`. This a PSX executable that can be run in an emulator like [pcsx-redux](https://github.com/grumpycoders/pcsx-redux/).
### Linux
#### Install your distribution's MIPS toolchain
In a terminal :
On Debian derivatives (Ubuntu, Mint...) :
```bash
sudo apt-get install gcc-mipsel-linux-gnu g++-mipsel-linux-gnu binutils-mipsel-linux-gnu
```
* If you want to compile pcsx-redux, you need a few more packages :
On Arch derivatives (Manjaro), the mipsel environment can be installed from [AUR](https://wiki.archlinux.org/index.php/Aur) : [cross-mipsel-linux-gnu-binutils](https://aur.archlinux.org/packages/cross-mipsel-linux-gnu-binutils/) and [cross-mipsel-linux-gnu-gcc](https://aur.archlinux.org/packages/cross-mipsel-linux-gnu-gcc/) using your [AURhelper](https://wiki.archlinux.org/index.php/AUR_helpers) of choice:
```bash
sudo apt-get install -y git make pkg-config clang g++ libfreetype6-dev libavcodec-dev libavformat-dev libavutil-dev libglfw3-dev libsdl2-dev libswresample-dev libuv1-dev zlib1g-dev
trizen -S cross-mipsel-linux-gnu-binutils cross-mipsel-linux-gnu-gcc
```
#### Nugget + PsyQ setup
See [here](https://github.com/grumpycoders/pcsx-redux#gnulinux-dependencies) if you're using an Arch derivative.
Let's do it all on the [CLI](https://en.wikipedia.org/wiki/Command-line_interface) !
2. Clone the pcsx-redux repo :
1. Install the git client :
```bash
git clone https://github.com/grumpycoders/pcsx-redux.git --recursive
sudo apt-get install git
```
3. Enter pcsx-redux folder:
2. Clone this repository :
```bash
cd pcsx-redux
git clone https://github.com/ABelliqueux/nolibgs_hello_worlds.git --recursive
```
4. Compile pcsx-redux :
```bash
3. Change to the repo's directory and get the PsyQ converted libraries:
```bash
cd nolibgs_hello_worlds
wget http://psx.arthus.net/sdk/Psy-Q/psyq-4_7-converted-light.zip
unzip psyq-4_7-converted-light.zip
```
4. Try your setup :
```bash
make
```
By default, this should build the `hello_world` example, and you should now have a `hello_world.ps-exe` file in `C:\psxdev\hello_world`. This a PSX executable that can be run in an emulator like [pcsx-redux](https://github.com/grumpycoders/pcsx-redux/).
If you encounter an error due to an old version of GCC (< 10) like something about `-fcoroutines`, then you can use **clang** ( min version 9) to compile `pcsx-redux` :
### MacOS
```bash
A [brew](https://brew.sh/) installation script can be found [here.](https://github.com/grumpycoders/pcsx-redux#macos).
CC=clang CXX=clang++ LD=clang++ make
```
5. Get the converted [PsyQ 4.7 libs](http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z) :
```bash
wget http://psx.arthus.net/sdk/Psy-Q/psyq-4.7-converted-full.7z
```
6. Extract this archive to `[...]pcsx-redux/src/mips/psyq/`, adapting the path ( the part after `-o`) in the command below to the folder you cloned pcsx-redux in :
## Compilation
```bash
7z x -o./src/mips/psyq/ psyq-4.7-converted-full.7z
```
In a terminal, `cd` to your psxdev setup directory and type `make all` to build all examples in their respective directories.
Your `pcsx-redux/src/mips/psyq/` directory should now contain an `include` and a `lib` folder with a bunch of files in each of them :
```bash
$tree ~/pcsx-redux/src/mips/psyq/
.
├── include
│   ├── abs.h
│   ├── ...
│   ├── strings.h
│   └── sys
│   ├── errno.h
│   ├── ...
│   └── types.h
├── lib
│   ├── libapi.a
│   ├── ...
│   └── libtap.a
└── tree
Alternatively, you can use `make example_name` to only build that example, i.e : `make hello_poly`.
3 directories, 82 files
```
7. That's it ! After that you can check everything's working by trying to compile some example code :
```bash
cd src/mips/psyq/cube
make
```
You should know have a 'cube.ps-exe' file in the folder. This is a PSX executable you can load with most emulators.
## Embedding binary data in a ps-exe
So, if you don't know it yet, the fun in PSX development is to be able to upload your exes on real hardware with a USB/Serial cable.
This means that the data you'll use in your program ( graphics, sounds, etc.) will have to be embedded in your exe in a binary form,
as you won't be able to stream them from the serial port.
*Well technically you could load them in memory before uploading your exe or stream them from a cd, but let's keep things simple for now.*
With our setup, this is quite easy !
1. In `pcsx-redux/src/mips/common.mk` , add the lines :
```mk
# convert TIM file to bin
%.o: %.tim
$(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O elf32-tradlittlemips -B mips $< $@
# convert VAG files to bin
%.o: %.vag
$(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O elf32-tradlittlemips -B mips $< $@
```
If you pay attention, you can see that's the same command, but for different file types. TIM files are bitmap images and VAG is the sound format used in this example.
Each time you'll want to add a file type, duplicate and change `%.vag` to `%.filetype`
Then, in your project folder, copy the makefile from the cube example :
```bash
mkdir new_project && cd new_project
cp ../cube/Makefile ../
```
All you have to do now is add the files you wish to embed to the SRCS variable, without forgetting the \ :
```bash
SRCS = main.c \
../common/crt0/crt0.s \
file_to_embed.ext \
```
2. So this part takes care of converting our data to binary. Now to access them from your program, use this in your sources :
```c
extern ulong _binary_filename_extension_start[];
extern ulong _binary_filename_extension_end[];
extern ulong _binary_bowsht_tim_length[];
```
The filename variable must begin with `_binary_` followed by the full path of your file, with . and / replaced by _ (underscore), and end with `_start[];` or `_end[];` or `_length[];` [source](https://discord.com/channels/642647820683444236/663664210525290507/780866265077383189)
`_start` and `_end` are pointers, while `_length` is a constant.
That's it! When you'll type `make` next time, it should convert your files to .o, then include them in your ps-exe.
## Compiling the examples in this repo
All you have to do is uncomment the corresponding rules in `Makefile` then compile with `make`.
If you want to remove all the files generated by the compilation process, type `make clean`.
# Links and Doc
* [Getting started with PSX dev](https://psx.arthus.net/starting.html)
* [Ps1 dev ressource center](https://ps1.consoledev.net/)
* [PsyQ docs](http://psx.arthus.net/sdk/Psy-Q/DOCS/)
* [Ps1 dev links](https://ps1.consoledev.net/)
* [psxdev.net](http://psxdev.net/)
* [psxdev Discord](https://discord.com/invite/N2mmwp?utm_source=Discord%20Widget&utm_medium=Connect)
* [psxdev Discord](https://discord.com/invite/N2mmwp)
# Credits, thanks, hugs

38
common.mk Normal file
View File

@ -0,0 +1,38 @@
# If you change this to exe, you'll have to rename the file ./thirdparty/nugget/ps-exe.ld too.
TYPE = ps-exe
SRCS += ../thirdparty/nugget/common/crt0/crt0.s
CPPFLAGS += -I../thirdparty/nugget/psyq/include -I../psyq-4_7-converted/include -I../psyq-4.7-converted-full/include -I../psyq/include
LDFLAGS += -L../thirdparty/nugget/psyq/lib -L../psyq-4_7-converted/lib -L../psyq-4.7-converted-full/lib -L../psyq/lib
LDFLAGS += -Wl,--start-group
LDFLAGS += -lapi
LDFLAGS += -lc
LDFLAGS += -lc2
LDFLAGS += -lcard
LDFLAGS += -lcomb
LDFLAGS += -lds
LDFLAGS += -letc
LDFLAGS += -lgpu
LDFLAGS += -lgs
LDFLAGS += -lgte
LDFLAGS += -lgun
LDFLAGS += -lhmd
LDFLAGS += -lmath
LDFLAGS += -lmcrd
LDFLAGS += -lmcx
LDFLAGS += -lpad
LDFLAGS += -lpress
LDFLAGS += -lsio
LDFLAGS += -lsnd
LDFLAGS += -lspu
LDFLAGS += -ltap
LDFLAGS += -lcd
LDFLAGS += -Wl,--end-group
# convert TIM file to bin
%.o: %.tim
$(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O elf32-tradlittlemips -B mips $< $@
# convert VAG files to bin
%.o: %.vag
$(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O elf32-tradlittlemips -B mips $< $@

6
hello_2pads/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_2pads
SRCS = hello_2pads.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

417
hello_2pads/hello_2pads.c Normal file
View File

@ -0,0 +1,417 @@
// hello_libpad example
//
// We're using libpad this time.
// You can use the classic controller, analog, wheel, gun buttons or mouse
//
// Schnappy - 12/2020
//
// Based on : ../psyq/addons/scea/CNTRL/PAD.C
//
// Controller demo
// Written by Mike Fulton
// Last Modified 6:25pm, 11/15/96
// Copyright (c) 1996 Sony Computer Entertainment America
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#include <libapi.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define MARGINX 32 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 7 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
// Pad stuff
// Structure for RAW hardware-based light gun position values
typedef struct
{
unsigned short v_count; // Y-axis (vertical scan counter)
unsigned short h_count; // H-axis (horizontal pixel clock value)
} Gun_Position;
// Structure for storing processed controller data
typedef struct
{
int xpos, ypos; // Stored position for sprite(s)
int xpos2, ypos2; // controlled by this controller.
unsigned char status; // These 8 values are obtained
unsigned char type; // directly from the controller
unsigned char button1; // buffer we installed with InitPAD.
unsigned char button2;
unsigned char analog0;
unsigned char analog1;
unsigned char analog2;
unsigned char analog3;
} Controller_Data;
// All-purpose controller data buffer
typedef struct
{
unsigned char pad[34]; // 8-bytes w/o Multi-Tap, 34-bytes w/Multi-Tap
} Controller_Buffer;
Controller_Buffer controllers[2]; // Buffers for reading controllers
Controller_Data theControllers[8]; // Processed controller data
void init(void)
{
ResetGraph(0);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
void get_digital_direction( Controller_Data *c, int buttondata ) // get analog stick values
{
int i;
i = ~(buttondata);
if( i & 0x80 )
c->xpos -= 1;
if( i & 0x20 )
c->xpos += 1;
if( i & 0x40 )
c->ypos += 1;
if( i & 0x10 )
c->ypos -= 1;
}
void read_controller( Controller_Data *c, unsigned char *buf, int port ) // get the raw values from controller
{
register int mouse_x, mouse_y, x;
register Gun_Position *g;
c->status = buf[0]; // Copy over raw controller data
c->type = buf[1];
c->button1 = buf[2];
c->button2 = buf[3];
c->analog0 = buf[4];
c->analog1 = buf[5];
c->analog2 = buf[6];
c->analog3 = buf[7];
if( buf[0] == 0xff ) // If controller returns BAD status then bail on it.
{
c->type = 0;
return;
}
// Look at the controller type code & process controller data as indicated
switch( c->type )
{
case 0x12: // Sony Mouse
mouse_x = buf[4];
mouse_y = buf[5];
if( mouse_x & 0x80 )
mouse_x |= 0xffffff80;
if( mouse_y & 0x80 )
mouse_y |= 0xffffff80;
c->xpos += mouse_x;
c->ypos += mouse_y;
break;
case 0x23: // Namco negCon
// Steering wheel
// Sankyo Pachinko controler
get_digital_direction( c, buf[2] );
break;
case 0x53: // Analog 2-stick
get_digital_direction( c, buf[2] );
break;
case 0x41: // Standard Sony PAD controller
get_digital_direction( c, buf[2] );
break;
default: // If don't know what it is, treat it like standard controller
get_digital_direction( c, buf[2] );
break;
}
}
int main(void)
{
TILE * PADL; // Tile primitives
TILE * TRIGGERL;
TILE * PADR;
TILE * TRIGGERR;
TILE * START, * SELECT;
init();
InitPAD(controllers[0].pad, 34, controllers[1].pad, 34);
StartPAD();
while (1)
{
read_controller( &theControllers[0], &controllers[0].pad[0], 0 ); // Read controllers
read_controller( &theControllers[1], &controllers[1].pad[0], 1 );
ClearOTagR(ot[db], OTLEN);
// D-cross
PADL = (TILE *)nextpri;
setTile(PADL);
setRGB0(PADL, 80, 180, 255);
setXY0(PADL, CENTERX - 80, CENTERY);
setWH(PADL, 24, 24);
addPrim(ot[db], PADL);
nextpri += sizeof(TILE);
// L1+L2
TRIGGERL = (TILE *)nextpri;
setTile(TRIGGERL);
setRGB0(TRIGGERL, 255, 0, 0);
setXY0(TRIGGERL, CENTERX - 80, CENTERY - 80);
setWH(TRIGGERL, 24, 24);
addPrim(ot[db], TRIGGERL);
nextpri += sizeof(TILE);
// /\, X, O, []
PADR = (TILE *)nextpri;
setTile(PADR);
setRGB0(PADR, 0, 255, 0);
setXY0(PADR, CENTERX + 50, CENTERY);
setWH(PADR, 24, 24);
addPrim(ot[db], PADR);
nextpri += sizeof(TILE);
// R1+R2
TRIGGERR = (TILE *)nextpri;
setTile(TRIGGERR);
setRGB0(TRIGGERR, 255, 0, 255);
setXY0(TRIGGERR, CENTERX + 50, CENTERY -80);
setWH(TRIGGERR, 24, 24);
addPrim(ot[db], TRIGGERR);
nextpri += sizeof(TILE);
// START + SELECT
START = (TILE *)nextpri;
setTile(START);
setRGB0(START, 240, 240, 240);
setXY0(START, CENTERX - 16, CENTERY - 36);
setWH(START, 24, 24);
addPrim(ot[db], START);
nextpri += sizeof(TILE);
// D-pad
switch(theControllers[0].button1){
case 0xDF: // Right
PADL->x0 = CENTERX - 64;
break;
case 0x7F: // Left
PADL->x0 = CENTERX - 96;
break;
case 0xEF: // Up
PADL->y0 = CENTERY - 16;
break;
case 0xBF: // Down
PADL->y0 = CENTERY + 16;
break;
// Start & Select
case 0xF7:
START->w = 32; START->h = 32;START->x0 -= 4;START->y0 -= 4; // START
break;
case 0xFE: // SELECT
START->r0 = 0;
break;
// Dualshock L3 + R3
case 0xFD: // L3
TRIGGERL->w += 10;
TRIGGERL->h += 10;
break;
case 0xFB: //R3
TRIGGERR->w += 10;
TRIGGERR->h += 10;
break;
}
// Buttons
switch(theControllers[0].button2){
case 0xDF: // ⭘
PADR->x0 = CENTERX + 66;
break;
case 0x7F: // ⬜
PADR->x0 = CENTERX + 34;
break;
case 0xEF: // △
PADR->y0 = CENTERY - 16;
break;
case 0xBF: //
PADR->y0 = CENTERY + 16;
break;
// Shoulder buttons
case 0xFB: // L1
TRIGGERL->y0 = CENTERY - 64;
break;
case 0xFE: // L2
TRIGGERL->y0 = CENTERY - 96;
break;
case 0xF7: // R1
TRIGGERR->y0 = CENTERY - 96;
break;
case 0xFD: // R2
TRIGGERR->y0 = CENTERY - 64;
break;
// Mouse buttons
case 0xF4: // Mouse Left click
PADL->w += 10;
PADL->h += 10;
break;
case 0xF8: // Mouse Right click
PADL->w -= 10;
PADL->h -= 10;
break;
}
FntPrint("Hello 2 pads!\n\n");
FntPrint( "Pad 1 : %02x\nButtons:%02x %02x, Stick:%02x %02x %02x %02x\n",
theControllers[0].type, // Controller type : 00 == none, 41 == standard, 73 == analog/dualshock, 12 == mouse, 23 == steering wheel, 63 == gun, 53 == analog joystick
theControllers[0].button1, //
theControllers[0].button2,
theControllers[0].analog0,
theControllers[0].analog1,
theControllers[0].analog2,
theControllers[0].analog3 );
FntPrint( "Pad 2 : %02x\nButtons:%02x %02x, Stick:%02x %02x %02x %02x\n",
theControllers[1].type, // Controller type : 00 == none, 41 == standard, 73 == analog/dualshock, 12 == mouse, 23 == steering wheel, 63 == gun, 53 == analog joystick
theControllers[1].button1, //
theControllers[1].button2,
theControllers[1].analog0, // R3 horizontal
theControllers[1].analog1, // R3 vertical
theControllers[1].analog2, // L3 horizontal
theControllers[1].analog3 ); // L3 vertical
FntFlush(-1);
display();
}
return 0;
}

6
hello_cube/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_cube
SRCS = hello_cube.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

167
hello_cube/cube.c Normal file
View File

@ -0,0 +1,167 @@
SVECTOR modelCube_mesh[] = {
{ -128,128,128 },
{ 128,128,128 },
{ 128,128,-128 },
{ -128,128,-128 },
{ -128,-128,128 },
{ 128,-128,128 },
{ 128,-128,-128 },
{ -128,-128,-128 }
};
SVECTOR modelCube_normal[] = {
2365,-2365,-2365, 0,
-2365,-2365,-2365, 0,
-2365,-2365,2365, 0,
2365,-2365,2365, 0,
2365,2365,-2365, 0,
-2365,2365,-2365, 0,
-2365,2365,2365, 0,
2365,2365,2365, 0
};
CVECTOR modelCube_color[] = {
255,237,0, 0,
255,235,0, 0,
255,236,0, 0,
255,2,0, 0,
254,3,0, 0,
255,8,0, 0,
229,0,255, 0,
229,0,255, 0,
229,0,255, 0,
5,16,250, 0,
0,12,255, 0,
0,12,255, 0,
4,251,25, 0,
0,255,26, 0,
0,255,26, 0,
0,248,255, 0,
0,248,255, 0,
0,248,255, 0,
255,237,0, 0,
255,237,0, 0,
255,235,0, 0,
255,2,0, 0,
255,6,2, 0,
254,3,0, 0,
229,0,255, 0,
232,21,232, 0,
229,0,255, 0,
5,16,250, 0,
2,13,253, 0,
0,12,255, 0,
4,251,25, 0,
0,255,26, 0,
0,255,26, 0,
0,248,255, 0,
0,248,255, 0,
0,248,255, 0
};
int modelCube_index[] = {
0,2,3,
7,5,4,
4,1,0,
5,2,1,
2,7,3,
0,7,4,
0,1,2,
7,6,5,
4,5,1,
5,6,2,
2,6,7,
0,3,7
};
TMESH modelCube = {
modelCube_mesh,
modelCube_normal,
0,
modelCube_color,
12
};
SVECTOR modelCube1_mesh[] = {
{ -128,128,128 },
{ 128,128,128 },
{ 128,128,-128 },
{ -128,128,-128 },
{ -128,-128,128 },
{ 128,-128,128 },
{ 128,-128,-128 },
{ -128,-128,-128 }
};
SVECTOR modelCube1_normal[] = {
2365,-2365,-2365, 0,
-2365,-2365,-2365, 0,
-2365,-2365,2365, 0,
2365,-2365,2365, 0,
2365,2365,-2365, 0,
-2365,2365,-2365, 0,
-2365,2365,2365, 0,
2365,2365,2365, 0
};
CVECTOR modelCube1_color[] = {
255,237,0, 0,
255,235,0, 0,
255,236,0, 0,
255,2,0, 0,
254,3,0, 0,
255,8,0, 0,
229,0,255, 0,
229,0,255, 0,
229,0,255, 0,
5,16,250, 0,
0,12,255, 0,
0,12,255, 0,
4,251,25, 0,
0,255,26, 0,
0,255,26, 0,
0,248,255, 0,
0,248,255, 0,
0,248,255, 0,
255,237,0, 0,
255,237,0, 0,
255,235,0, 0,
255,2,0, 0,
255,6,2, 0,
254,3,0, 0,
229,0,255, 0,
232,21,232, 0,
229,0,255, 0,
5,16,250, 0,
2,13,253, 0,
0,12,255, 0,
4,251,25, 0,
0,255,26, 0,
0,255,26, 0,
0,248,255, 0,
0,248,255, 0,
0,248,255, 0
};
int modelCube1_index[] = {
0,2,3,
7,5,4,
4,1,0,
5,2,1,
2,7,3,
0,7,4,
0,1,2,
7,6,5,
4,5,1,
5,6,2,
2,6,7,
0,3,7
};
TMESH modelCube1 = {
modelCube1_mesh,
modelCube1_normal,
0,
modelCube1_color,
12
};

178
hello_cube/hello_cube.c Normal file
View File

@ -0,0 +1,178 @@
/* primdrawG.c, by Schnappy, 12-2020
- Draw a gouraud shaded mesh exported as a TMESH by the blender <= 2.79b plugin io_export_psx_tmesh.py
based on primdraw.c by Lameguy64 (http://www.psxdev.net/forum/viewtopic.php?f=64&t=537)
2014 Meido-Tek Productions.
Demonstrates:
- Using a primitive OT to draw triangles without libgs.
- Using the GTE to rotate, translate, and project 3D primitives.
Controls:
Start - Toggle interactive/non-interactive mode.
Select - Reset object's position and angles.
L1/L2 - Move object closer/farther.
L2/R2 - Rotate object (XY).
Up/Down/Left/Right - Rotate object (XZ/YZ).
Triangle/Cross/Square/Circle - Move object up/down/left/right.
*/
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <libgte.h>
#include <libgpu.h>
#include <libetc.h>
#include <stdio.h>
// Sample vector model
#include "../includes/cube.c"
#define VMODE 0
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define OTLEN 2048 // Maximum number of OT entries
#define PRIMBUFFLEN 32768 // Maximum number of POLY_GT3 primitives
// Display and draw environments, double buffered
DISPENV disp[2];
DRAWENV draw[2];
u_long ot[2][OTLEN]; // Ordering table (contains addresses to primitives)
char primbuff[2][PRIMBUFFLEN] = {0}; // Primitive list // That's our prim buffer
char * nextpri = primbuff[0]; // Primitive counter
short db = 0; // Current buffer counter
// Prototypes
void init(void);
void display(void);
//~ void LoadTexture(u_long * tim, TIM_IMAGE * tparam);
void init(){
// Reset the GPU before doing anything and the controller
PadInit(0);
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX, CENTERY); // x, y offset
SetGeomScreen(CENTERX); // Distance between eye and screen
// Set the display and draw environments
SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 0, 128, 255);
setRGB0(&draw[1], 0, 128, 255);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Init font system
FntLoad(960, 0);
FntOpen(16, 16, 196, 64, 0, 256);
}
void display(void){
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main() {
int i;
int PadStatus;
int TPressed=0;
int AutoRotate=1;
long t, p, OTz, Flag; // t == vertex count, p == depth cueing interpolation value, OTz == value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143
POLY_G3 *poly = {0}; // pointer to a POLY_G4
SVECTOR Rotate={ 0 }; // Rotation coordinates
VECTOR Trans={ 0, 0, CENTERX * 3, 0 }; // Translation coordinates
// Scaling coordinates
VECTOR Scale={ ONE/2, ONE/2, ONE/2, 0 }; // ONE == 4096
MATRIX Matrix={0}; // Matrix data for the GTE
init();
// Main loop
while (1) {
// Read pad status
PadStatus = PadRead(0);
if (AutoRotate == 0) {
if (PadStatus & PADL1) Trans.vz -= 4;
if (PadStatus & PADR1) Trans.vz += 4;
if (PadStatus & PADL2) Rotate.vz -= 8;
if (PadStatus & PADR2) Rotate.vz += 8;
if (PadStatus & PADLup) Rotate.vx -= 8;
if (PadStatus & PADLdown) Rotate.vx += 8;
if (PadStatus & PADLleft) Rotate.vy -= 8;
if (PadStatus & PADLright) Rotate.vy += 8;
if (PadStatus & PADRup) Trans.vy -= 2;
if (PadStatus & PADRdown) Trans.vy += 2;
if (PadStatus & PADRleft) Trans.vx -= 2;
if (PadStatus & PADRright) Trans.vx += 2;
if (PadStatus & PADselect) {
Rotate.vx = Rotate.vy = Rotate.vz = 0;
Scale.vx = Scale.vy = Scale.vz = ONE/2;
Trans.vx = Trans.vy = 0;
Trans.vz = CENTERX * 3;
}
}
if (PadStatus & PADstart) {
if (TPressed == 0) {
AutoRotate = (AutoRotate + 1) & 1;
Rotate.vx = Rotate.vy = Rotate.vz = 0;
Scale.vx = Scale.vy = Scale.vz = ONE/2;
Trans.vx = Trans.vy = 0;
Trans.vz = CENTERX * 3;
}
TPressed = 1;
} else {
TPressed = 0;
}
if (AutoRotate) {
Rotate.vy += 8; // Pan
Rotate.vx += 8; // Tilt
//~ Rotate.vz += 8; // Roll
}
// Clear the current OT
ClearOTagR(ot[db], OTLEN);
// Convert and set the matrixes
RotMatrix(&Rotate, &Matrix);
TransMatrix(&Matrix, &Trans);
ScaleMatrix(&Matrix, &Scale);
SetRotMatrix(&Matrix);
SetTransMatrix(&Matrix);
// Render the sample vector model
t=0;
// modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...
for (i = 0; i < (modelCube.len*3); i += 3) {
poly = (POLY_G3 *)nextpri;
// Initialize the primitive and set its color values
SetPolyG3(poly);
setRGB0(poly, modelCube.c[i].r , modelCube.c[i].g , modelCube.c[i].b);
setRGB1(poly, modelCube.c[i+2].r, modelCube.c[i+2].g, modelCube.c[i+2].b);
setRGB2(poly, modelCube.c[i+1].r, modelCube.c[i+1].g, modelCube.c[i+1].b);
// Rotate, translate, and project the vectors and output the results into a primitive
OTz = RotTransPers(&modelCube_mesh[modelCube_index[t]] , (long*)&poly->x0, &p, &Flag);
OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+2]], (long*)&poly->x1, &p, &Flag);
OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+1]], (long*)&poly->x2, &p, &Flag);
// Sort the primitive into the OT
OTz /= 3;
if ((OTz > 0) && (OTz < OTLEN))
AddPrim(&ot[db][OTz-2], poly);
nextpri += sizeof(POLY_G3);
t+=3;
}
FntPrint("Hello gouraud shaded cube!\n");
FntFlush(-1);
display();
}
return 0;
}

7
hello_cubetex/Makefile Normal file
View File

@ -0,0 +1,7 @@
TARGET = hello_cubetex
SRCS = hello_cubetex.c \
../TIM/cubetex.tim \
include ../common.mk
include ../thirdparty/nugget/common.mk \

132
hello_cubetex/cubetex.c Normal file
View File

@ -0,0 +1,132 @@
SVECTOR modelCube_mesh[] = {
{20.0,19.999998807907104,-20.0},
{20.0,-20.0,-20.0},
{-20.00000238418579,-19.999996423721313,-20.0},
{-19.999992847442627,20.000007152557373,-20.0},
{20.000009536743164,19.99998927116394,20.0},
{19.99998688697815,-20.000011920928955,20.0},
{-20.000007152557373,-19.999992847442627,20.0},
{-19.999998807907104,20.0,20.0}
};
SVECTOR modelCube_normal[] = {
0.0,-0.0,-1.0,0,
0.0,0.0,1.0,0,
1.0,0.0,-2.384185791015625e-07,0,
-8.940696716308594e-08,-1.0,-2.9802325229866256e-07,0,
-1.0,2.384185791015625e-07,-1.4901158351676713e-07,0,
2.6822084464583895e-07,1.0,2.3841852225814364e-07,0,
0.0,0.0,-1.0,0,
0.0,-0.0,1.0,0,
1.0,-5.662441253662109e-07,3.2782537573439186e-07,0,
-4.768372150465439e-07,-1.0,8.940690321423972e-08,0,
-1.0,2.0861631355728605e-07,-1.1920931797249068e-07,0,
2.0861631355728605e-07,1.0,1.7881397695873602e-07,0
};
SVECTOR modelCube_uv[] = {
83.71398162841797,83.71389770507812, 0, 0,
125.03179168701172,42.396141052246094, 0, 0,
83.71398162841797,42.396141052246094, 0, 0,
125.03179168701172,83.71392059326172, 0, 0,
83.71398162841797,125.03166770935059, 0, 0,
125.03179168701172,125.03169059753418, 0, 0,
1.0784510374069214,83.71392059326172, 0, 0,
42.39619445800781,125.03169059753418, 0, 0,
42.39621353149414,83.71392440795898, 0, 0,
42.39621353149414,125.03166770935059, 0, 0,
83.71398162841797,83.71392440795898, 0, 0,
42.39621353149414,83.71390151977539, 0, 0,
42.39619445800781,1.0783309936523438, 0, 0,
1.0784281492233276,42.39611053466797, 0, 0,
42.39619445800781,42.39612579345703, 0, 0,
42.39619064331055,83.71392059326172, 0, 0,
1.0784281492233276,42.396141052246094, 0, 0,
1.0784281492233276,83.71392059326172, 0, 0,
83.71398162841797,83.71389770507812, 0, 0,
125.03179168701172,83.71390151977539, 0, 0,
125.03179168701172,42.396141052246094, 0, 0,
125.03179168701172,83.71392059326172, 0, 0,
83.71399688720703,83.71392440795898, 0, 0,
83.71398162841797,125.03166770935059, 0, 0,
1.0784510374069214,83.71392059326172, 0, 0,
1.0784281492233276,125.03169059753418, 0, 0,
42.39619445800781,125.03169059753418, 0, 0,
42.39621353149414,125.03166770935059, 0, 0,
83.71398162841797,125.03169059753418, 0, 0,
83.71398162841797,83.71392440795898, 0, 0,
42.39619445800781,1.0783309936523438, 0, 0,
1.0784281492233276,1.0783309936523438, 0, 0,
1.0784281492233276,42.39611053466797, 0, 0,
42.39619064331055,83.71392059326172, 0, 0,
42.39619445800781,42.396141052246094, 0, 0,
1.0784281492233276,42.396141052246094, 0, 0
};
CVECTOR modelCube_color[] = {
255,255,255, 0,
255,255,255, 0,
255,0,251, 0,
255,255,255, 0,
255,5,7, 0,
255,255,255, 0,
255,255,255, 0,
255,255,255, 0,
4,18,255, 0,
255,5,7, 0,
255,255,255, 0,
255,255,255, 0,
254,255,23, 0,
122,255,107, 0,
255,255,255, 0,
255,255,255, 0,
255,255,255, 0,
254,255,94, 0,
255,255,255, 0,
35,255,11, 0,
255,255,255, 0,
255,255,255, 0,
255,255,255, 0,
255,5,7, 0,
255,255,255, 0,
255,5,7, 0,
255,255,255, 0,
255,5,7, 0,
255,255,255, 0,
255,255,255, 0,
254,255,23, 0,
255,255,255, 0,
122,255,107, 0,
255,255,255, 0,
54,65,255, 0,
255,255,255, 0
};
int modelCube_index[] = {
0,2,3,
7,5,4,
4,1,0,
5,2,1,
2,7,3,
0,7,4,
0,1,2,
7,6,5,
4,5,1,
5,6,2,
2,6,7,
0,3,7
};
TMESH modelCube = {
modelCube_mesh,
modelCube_normal,
modelCube_uv,
modelCube_color,
12
};
extern unsigned long _binary____TIM_cubetex_tim_start[];
extern unsigned long _binary____TIM_cubetex_tim_end[];
extern unsigned long _binary____TIM_cubetex_tim_length;
TIM_IMAGE tim_cube;

View File

@ -0,0 +1,297 @@
/* primdrawG.c, by Schnappy, 12-2020
- Draw a gouraud shaded mesh exported as a TMESH by the blender <= 2.79b plugin io_export_psx_tmesh.py
based on primdraw.c by Lameguy64 (http://www.psxdev.net/forum/viewtopic.php?f=64&t=537)
2014 Meido-Tek Productions.
Demonstrates:
- Using a primitive OT to draw triangles without libgs.
- Using the GTE to rotate, translate, and project 3D primitives.
Controls:
Start - Toggle interactive/non-interactive mode.
Select - Reset object's position and angles.
L1/L2 - Move object closer/farther.
L2/R2 - Rotate object (XY).
Up/Down/Left/Right - Rotate object (XZ/YZ).
Triangle/Cross/Square/Circle - Move object up/down/left/right.
*/
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <libgte.h>
#include <libgpu.h>
#include <libetc.h>
#include <stdio.h>
// Sample vector model
#include "cubetex.c"
#define VMODE 0
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define OTLEN 2048 // Maximum number of OT entries
#define PRIMBUFFLEN 32768 // Maximum number of POLY_GT3 primitives
// Display and draw environments, double buffered
DISPENV disp[2];
DRAWENV draw[2];
u_long ot[2][OTLEN]; // Ordering table (contains addresses to primitives)
char primbuff[2][PRIMBUFFLEN] = {0}; // Primitive list // That's our prim buffer
//~ int primcnt=0; // Primitive counter
char * nextpri = primbuff[0]; // Primitive counter
short db = 0; // Current buffer counter
// Prototypes
void init(void);
void display(void);
void LoadTexture(u_long * tim, TIM_IMAGE * tparam);
void init(){
// Reset the GPU before doing anything and the controller
PadInit(0);
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX, CENTERY); // x, y offset
SetGeomScreen(CENTERX); // Distance between eye and screen
// Set the display and draw environments
SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 0, 0, 255);
setRGB0(&draw[1], 0, 0, 255);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Init font system
FntLoad(960, 0);
FntOpen(16, 16, 196, 64, 0, 256);
}
void display(void){
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
void LoadTexture(u_long * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous
OpenTIM(tim); // Open the tim binary data, feed it the address of the data in memory
ReadTIM(tparam); // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure
LoadImage(tparam->prect, tparam->paddr); // Transfer the data from memory to VRAM at position prect.x, prect.y
DrawSync(0); // Wait for the drawing to end
if (tparam->mode & 0x8){ // check 4th bit // If 4th bit == 1, TIM has a CLUT
LoadImage(tparam->crect, tparam->caddr); // Load it to VRAM at position crect.x, crect.y
DrawSync(0); // Wait for drawing to end
}
}
int main() {
int i;
int PadStatus;
int TPressed=0;
int AutoRotate=1;
long t, p, OTz, Flag; // t == vertex count, p == depth cueing interpolation value, OTz == value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143
POLY_GT3 *poly = {0}; // pointer to a POLY_G4
SVECTOR Rotate={ 0 }; // Rotation coordinates
VECTOR Trans={ 0, 0, CENTERX, 0 }; // Translation coordinates
// Scaling coordinates
VECTOR Scale={ ONE, ONE, ONE, 0 }; // ONE == 4096
MATRIX Matrix={0}; // Matrix data for the GTE
// Texture window
DR_MODE * dr_mode; // Pointer to dr_mode prim
RECT tws = {0, 0, 32, 32}; // Texture window coordinates : x, y, w, h
init();
LoadTexture(_binary____TIM_cubetex_tim_start, &tim_cube);
// Main loop
while (1) {
// Read pad status
PadStatus = PadRead(0);
if (AutoRotate == 0) {
if (PadStatus & PADL1) Trans.vz -= 4;
if (PadStatus & PADR1) Trans.vz += 4;
if (PadStatus & PADL2) Rotate.vz -= 8;
if (PadStatus & PADR2) Rotate.vz += 8;
if (PadStatus & PADLup) Rotate.vx -= 8;
if (PadStatus & PADLdown) Rotate.vx += 8;
if (PadStatus & PADLleft) Rotate.vy -= 8;
if (PadStatus & PADLright) Rotate.vy += 8;
if (PadStatus & PADRup) Trans.vy -= 2;
if (PadStatus & PADRdown) Trans.vy += 2;
if (PadStatus & PADRleft) Trans.vx -= 2;
if (PadStatus & PADRright) Trans.vx += 2;
if (PadStatus & PADselect) {
Rotate.vx = Rotate.vy = Rotate.vz = 0;
Scale.vx = Scale.vy = Scale.vz = ONE;
Trans.vx = Trans.vy = 0;
Trans.vz = CENTERX;
}
}
if (PadStatus & PADstart) {
if (TPressed == 0) {
AutoRotate = (AutoRotate + 1) & 1;
Rotate.vx = Rotate.vy = Rotate.vz = 0;
Scale.vx = Scale.vy = Scale.vz = ONE;
Trans.vx = Trans.vy = 0;
Trans.vz = CENTERX;
}
TPressed = 1;
} else {
TPressed = 0;
}
if (AutoRotate) {
Rotate.vy += 8; // Pan
Rotate.vx += 8; // Tilt
//~ Rotate.vz += 8; // Roll
}
// Clear the current OT
ClearOTagR(ot[db], OTLEN);
// Convert and set the matrixes
RotMatrix(&Rotate, &Matrix);
TransMatrix(&Matrix, &Trans);
ScaleMatrix(&Matrix, &Scale);
SetRotMatrix(&Matrix);
SetTransMatrix(&Matrix);
// Render the sample vector model
t=0;
// modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...
for (i = 0; i < (modelCube.len*3); i += 3) {
poly = (POLY_GT3 *)nextpri;
// Initialize the primitive and set its color values
SetPolyGT3(poly);
((POLY_GT3 *)poly)->tpage = getTPage(tim_cube.mode&0x3, 0,
tim_cube.prect->x,
tim_cube.prect->y
);
setRGB0(poly, modelCube.c[i].r , modelCube.c[i].g , modelCube.c[i].b);
setRGB1(poly, modelCube.c[i+2].r, modelCube.c[i+2].g, modelCube.c[i+2].b);
setRGB2(poly, modelCube.c[i+1].r, modelCube.c[i+1].g, modelCube.c[i+1].b);
setUV3(poly, modelCube.u[i].vx, modelCube.u[i].vy,
modelCube.u[i+2].vx, modelCube.u[i+2].vy,
modelCube.u[i+1].vx, modelCube.u[i+1].vy);
// Rotate, translate, and project the vectors and output the results into a primitive
OTz = RotTransPers(&modelCube_mesh[modelCube_index[t]] , (long*)&poly->x0, &p, &Flag);
OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+2]], (long*)&poly->x1, &p, &Flag);
OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+1]], (long*)&poly->x2, &p, &Flag);
// Sort the primitive into the OT
OTz /= 3;
if ((OTz > 0) && (OTz < OTLEN))
AddPrim(&ot[db][OTz-2], poly);
nextpri += sizeof(POLY_GT3);
t+=3;
}
dr_mode = (DR_MODE *)nextpri;
setDrawMode(dr_mode,1,0, getTPage(tim_cube.mode&0x3, 0,
tim_cube.prect->x,
tim_cube.prect->y), &tws); //set texture window
AddPrim(&ot[db], dr_mode);
nextpri += sizeof(DR_MODE);
FntPrint("Hello textured cube!\n");
FntFlush(-1);
display();
}
return 0;
}

6
hello_gte_opti/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_gte_opti
SRCS = hello_gte_opti.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

View File

@ -0,0 +1,239 @@
// Hello free cycles !
//
// Ref : /psyq/DOCS/Devrefs/Inlinref.pdf, p.18
// /psyq/psx/sample/scea/GTE
// https://psx-spx.consoledev.net/geometrytransformationenginegte/
// PSX / Z+
// screen /
//coordinate +-----X+
//system / |
// eye | Y+
//
// Credits, thanks : Nicolas Noble, Sickle, Lameguy64 @ psxdev discord : https://discord.com/invite/N2mmwp
// https://discord.com/channels/642647820683444236/663664210525290507/834831466100949002
#include <sys/types.h>
#include <stdio.h>
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
// OldWorld PsyQ has a inline_c.h file for inline GTE functions. We have to use the one at https://github.com/grumpycoders/pcsx-redux/blob/07f9b02d1dbb68f57a9f5b9773041813c55a4913/src/mips/psyq/include/inline_n.h
// because the real GTE commands are needed in nugget : https://psx-spx.consoledev.net/geometrytransformationenginegte/#gte-coordinate-calculation-commands
#include <inline_n.h>
// RAM -> CPU and CPU -> GTE macros :
#include "../includes/CPUMAC.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 >> 1 ) // Center of screen on x
#define CENTERY ( SCREENYRES >> 1 ) // Center of screen on y
#define MARGINX 0 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 7 // Text Field Height
#define OTLEN 10 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
// DCache setup
#define dc_camdirp ((sshort*) getScratchAddr(0))
#define dc_ip ((uchar*) getScratchAddr(1))
#define dc_opzp ((slong*) getScratchAddr(2))
#define dc_wmatp ((MATRIX*) getScratchAddr(3))
#define dc_cmatp ((MATRIX*) getScratchAddr(9))
#define dc_sxytbl ((DVECTOR*) getScratchAddr(15))
void init(void)
{
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
//~ SetGeomOffset(CENTERX,CENTERY);
gte_SetGeomOffset(CENTERX,CENTERY);
gte_SetGeomScreen(CENTERX);
// Set display environment
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
// Set draw environment
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
// If PAL, use 320x256, hence 256 - 240 = 16 / 2 = 8 px vertical offset
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
SetDispMask(1);
// Set background color
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
// Wait for drawing
DrawSync(0);
// Wait for vsync
VSync(1);
// Flip DISP and DRAW env
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
//~ SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
// Flip db index
db = !db;
// Get next primitive in buffer
nextpri = primbuff[db];
}
int main(void)
{
long p, flag, OTz;
SVECTOR rotVector = {0};
SVECTOR rotVector4 = {0}; // Initialize rotation vector {x, y, z} - ALWAYS !
VECTOR transVector = {0, 0, CENTERX, 0}; // Initialize translation vector {x, y, z}
SVECTOR vertPos[4] = {
{ 0, -32, 0, 0 }, // Vert 1
{ 32, 0, 0, 0 }, // Vert 2
{ -32, 0, 0, 0 },
{ 0, 32, 0, 0 }
}; // Vert 3
MATRIX workMatrix = {0};
POLY_F3 * poly = {0}; // pointer to a POLY_F4
POLY_F4 * poly4 = {0}; // pointer to a POLY_F4
init();
// Declare registers
register ulong ur0 asm("$16");
register ulong ur1 asm("$17");
register ulong ur2 asm("$18");
register ulong ur3 asm("$19");
register ulong ur4 asm("$20");
register ulong ur5 asm("$21");
while (1)
{
// Set Ordering table
ClearOTagR(ot[db], OTLEN);
// Cast next primitives in buffer as a POLY_F3 and a POLY_F4 (see display() )
poly = (POLY_F3 *)nextpri;
nextpri += sizeof(POLY_F3);
poly4 = (POLY_F4 *)nextpri;
// Set matrices - Move to left of screen
// Draw on the left part of the screen
transVector.vx = -CENTERX/2;
// Increment rotation angle on Y axis
rotVector.vy += 1;
// Find rotation matrix from vector, store in
RotMatrix_gte(&rotVector, &workMatrix);
// Ditto for translation
TransMatrix(&workMatrix, &transVector);
// Set the matrices we just found
gte_SetRotMatrix(&workMatrix);
gte_SetTransMatrix(&workMatrix);
// Draw a Tri and a Quad
// Copy Tri vertices from ram to cpu registers casting as ulong so that ur0 (len 32bits) contains vx and vy (2 * 8bits)
// Hence the use of vx, vz members
cpu_ldr(ur0,(ulong*)&vertPos[0].vx); // Put vx, vy value in ur0
cpu_ldr(ur1,(ulong*)&vertPos[0].vz); // Put vz, pad value in ur1
cpu_ldr(ur2,(ulong*)&vertPos[1].vx);
cpu_ldr(ur3,(ulong*)&vertPos[1].vz);
cpu_ldr(ur4,(ulong*)&vertPos[2].vx);
cpu_ldr(ur5,(ulong*)&vertPos[2].vz);
// Load the gte registers from the cpu registers (gte-cpu move 1 cycle) - mtc2 %0, $0;
cpu_gted0(ur0);
cpu_gted1(ur1);
cpu_gted2(ur2);
cpu_gted3(ur3);
cpu_gted4(ur4);
cpu_gted5(ur5);
// Tri RotTransPers3
// The two last cpu->gte copy will happen during the 2 nops in gte_rtpt()
gte_rtpt();
// Fill the cpu registers with the Quad vertices
cpu_ldr(ur0,(ulong*)&vertPos[0].vx);
cpu_ldr(ur1,(ulong*)&vertPos[0].vz);
cpu_ldr(ur2,(ulong*)&vertPos[1].vx);
cpu_ldr(ur3,(ulong*)&vertPos[1].vz);
cpu_ldr(ur4,(ulong*)&vertPos[2].vx);
cpu_ldr(ur5,(ulong*)&vertPos[2].vz);
// Get nclip value, and win two cycles
gte_nclip();
// Copy Tri 's screen coordinates from gte registers to d-cache.
gte_stsxy3c(&dc_sxytbl[0]);
// Set matrices - Move to right of screen
transVector.vx = CENTERX/2;
// Increment rot on X/Y axis
rotVector4.vy -= 1 ;
rotVector4.vx -= 1 ;
// Set matrices
RotMatrix_gte(&rotVector4, &workMatrix);
TransMatrix(&workMatrix, &transVector);
gte_SetRotMatrix(&workMatrix);
gte_SetTransMatrix(&workMatrix);
// Load the gte registers from the cpu registers (gte-cpu move 1 cycle) - mtc2 %0, $0;
cpu_gted0(ur0);
cpu_gted1(ur1);
cpu_gted2(ur2);
cpu_gted3(ur3);
cpu_gted4(ur4);
cpu_gted5(ur5);
// Quad RotTransPers3
// Getting 2 cycles back thanks to nops
gte_rtpt();
// gte_nclip() has 2 nops, lets use them to load the remaining vertex data from ram->cpu register
cpu_ldr(ur0,(ulong*)&vertPos[3].vx);
cpu_ldr(ur1,(ulong*)&vertPos[3].vz);
// Calculate nclip (outer product)
gte_nclip();
// Copy result to d-cache + 3
gte_stsxy3c(&dc_sxytbl[3]);
// Copy from cpu-gte
cpu_gted0(ur0);
cpu_gted1(ur1);
// Quad last vertex RotTransPers
// These two last cpu->gte load are free :p
gte_rtps();
gte_nclip();
// Copy last vertex value to d-cache
gte_stsxy(&dc_sxytbl[6]);
// Get p, flag, OTz
gte_stdp(&p);
gte_stflg(&flag);
gte_stszotz(&OTz);
// That's 10 cycles we won back ?
// Copy vertices data from d-cache to ram
// Tri
*(unsigned long long*)&poly->x0 = *(unsigned long long*)&dc_sxytbl[0];
*(ulong*)&poly->x2 = *(ulong*)&dc_sxytbl[2];
// Quad
*(unsigned long long*)&poly4->x0 = *(unsigned long long*)&dc_sxytbl[3];
*(unsigned long long*)&poly4->x2 = *(unsigned long long*)&dc_sxytbl[5];
// Initialize polygons
setPolyF3(poly);
setRGB0(poly, 255, 0, 255);
setPolyF4(poly4);
setRGB0(poly4, 0, 255, 255);
// Add to OT
addPrim(ot[db], poly);
addPrim(ot[db], poly4);
// Display text
FntPrint("Hello Free cycles !\n");
FntFlush(-1);
display();
}
return 0;
}

6
hello_light/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_light
SRCS = hello_light.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

276
hello_light/hello_light.c Normal file
View File

@ -0,0 +1,276 @@
/* hello_light.c, by Schnappy, 06-2021
- Demonstrates setting and using light sources in 3D without libgs.
Controls:
Start - Toggle interactive/non-interactive mode.
Select - Reset object's position and angles.
L1/L2 - Move object closer/farther.
L2/R2 - Rotate object (XY).
Up/Down/Left/Right - Rotate object (XZ/YZ).
Triangle/Cross/Square/Circle - Move object up/down/left/right.
based on primdraw.c by Lameguy64 (http://www.psxdev.net/forum/viewtopic.php?f=64&t=537)
2014 Meido-Tek Productions.
*/
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <libgte.h>
#include <libgpu.h>
#include <libetc.h>
#include <stdio.h>
// Sample vector model
#include "../includes/cube.c"
#define VMODE 0
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define OTLEN 2048 // Maximum number of OT entries
#define PRIMBUFFLEN 32768 // Maximum number of POLY_GT3 primitives
// Display and draw environments, double buffered
DISPENV disp[2];
DRAWENV draw[2];
u_long ot[2][OTLEN]; // Ordering table (contains addresses to primitives)
char primbuff[2][PRIMBUFFLEN] = {0}; // Primitive list // That's our prim buffer
char * nextpri = primbuff[0]; // Primitive counter
short db = 0; // Current buffer counter
long t, p, OTz, Flag; // t == vertex count, p == depth cueing interpolation value, OTz == value to create Z-ordered OT, Flag == see LibOver47.pdf, p.143
// Lighting
// See PsyQ's LibOver47.pdf, p.133 for more details on the purpose of each component and full calculations.
// Far color : This is the color used to fade to when the mesh is far from the cam (NearFog)
CVECTOR BGc = {150, 50, 75, 0};
// Back color
VECTOR BKc = {128, 128, 128, 0};
// Light rotation angle
SVECTOR lgtang = {0, 0, 0};
// These will be used to store the light rotation matrix, cube rotation matrix, and composite light matrix.
MATRIX rotlgt, rotcube, light;
// Local Light Matrix : Direction and reach of each light source.
// Each light points in the direction aligned with the axis, hence direction is in the same coordinate system as the PSX (see l.23-30 of this file)
// Negative/positive value denotes light direction on corresponding axis
// -4096 > Value < 4096 denotes reach/intensity of light source
MATRIX lgtmat = {
// X Y Z
-ONE, -ONE, ONE, // Lightsource 1 : here, the light source is at the Bottom-Left of the screen, and points into the screen.
0, 0, 0, // Lightsource 2
0, 0, 0, // Lightsource 3
};
// Local Color Matrix
// Set color of each light source (L)
// Value range : 0 > x < 4096
MATRIX cmat = {
// L1 L2 L3
4096, 0, 0, // R
4096, 0, 0, // G
4096, 0, 0 // B
};
// Prototypes
void init(void);
void display(void);
//~ void LoadTexture(u_long * tim, TIM_IMAGE * tparam);
void init(){
// Reset the GPU before doing anything and the controller
PadInit(0);
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX, CENTERY); // x, y offset
SetGeomScreen(CENTERX); // Distance between eye and screen
// Set the display and draw environments
SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
// Set light env
// Set far color
SetFarColor( BGc.r, BGc.g, BGc.b );
// Set Ambient color
SetBackColor( BKc.vx, BKc.vy, BKc.vz );
// Set Color matrix
SetColorMatrix(&cmat);
// Set Fog settings
SetFogNearFar( 1200, 2200, SCREENXRES );
setRGB0(&draw[0], 0, 0, 255);
setRGB0(&draw[1], 0, 0, 255);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Init font system
FntLoad(960, 0);
FntOpen(16, 16, 196, 64, 0, 256);
}
void display(void){
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main() {
int i;
int PadStatus;
int TPressed=0;
int AutoRotate=1;
// Rotating cube
POLY_G3 * poly;
SVECTOR Rotate={ ONE/6,ONE/6,ONE/6 }; // Rotation coordinates
VECTOR Trans={ -SCREENXRES/2, 0, CENTERX * 3, 0 }; // Translation coordinates
VECTOR Scale={ ONE/2, ONE/2, ONE/2, 0 }; // Scaling coordinates : ONE == 4096
MATRIX Matrix={0}; // Matrix data for the GTE
// Static cube
POLY_G3 * poly1; // pointer to a POLY_G4
SVECTOR Rotate1={ ONE/6, ONE/6, ONE/6, 0 }; // Rotation coordinates
VECTOR Trans1={ SCREENXRES/2, 0, CENTERX * 3, 0 }; // Translation coordinates
VECTOR Scale1={ ONE/2, ONE/2, ONE/2, 0 }; // Scaling coordinates : ONE == 4096
MATRIX Matrix1={0}; // Matrix data for the GTE
init();
// Main loop
while (1) {
// Read pad status
PadStatus = PadRead(0);
if (AutoRotate == 0) {
if (PadStatus & PADL1) Trans.vz -= 4;
if (PadStatus & PADR1) Trans.vz += 4;
if (PadStatus & PADL2) Rotate.vz -= 8;
if (PadStatus & PADR2) Rotate.vz += 8;
if (PadStatus & PADLup) Rotate.vx -= 8;
if (PadStatus & PADLdown) Rotate.vx += 8;
if (PadStatus & PADLleft) Rotate.vy -= 8;
if (PadStatus & PADLright) Rotate.vy += 8;
if (PadStatus & PADRup) Trans.vy -= 2;
if (PadStatus & PADRdown) Trans.vy += 2;
if (PadStatus & PADRleft) Trans.vx -= 2;
if (PadStatus & PADRright) Trans.vx += 2;
}
if (PadStatus & PADstart) {
if (TPressed == 0) {
AutoRotate = (AutoRotate + 1) & 1;
Rotate.vy = Rotate.vx = Rotate.vz = ONE/6;
Scale.vx = Scale.vy = Scale.vz = ONE/2;
Trans.vx = -SCREENXRES/2;
Trans.vy = 0;
Trans.vz = CENTERX * 3;
}
TPressed = 1;
} else {
TPressed = 0;
}
if (AutoRotate) {
Rotate.vy += 8; // Pan
Rotate.vx += 8; // Tilt
//~ Rotate.vz += 8; // Roll
}
// Clear the current OT
ClearOTagR(ot[db], OTLEN);
// Render the sample vector model
t=0;
// modelCube is a TMESH, len member == # vertices, but here it's # of triangle... So, for each tri * 3 vertices ...
for (i = 0; i < (modelCube.len*3); i += 3) {
poly = (POLY_G3 *)nextpri;
// Initialize the primitive and set its color values
SetPolyG3(poly);
// Rotate, translate, and project the vectors and output the results into a primitive
// Could be replaced with one call with RotTransPers3()
OTz = RotTransPers(&modelCube_mesh[modelCube_index[t]] , (long*)&poly->x0, &p, &Flag);
OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+2]], (long*)&poly->x1, &p, &Flag);
OTz += RotTransPers(&modelCube_mesh[modelCube_index[t+1]], (long*)&poly->x2, &p, &Flag);
// Find light color
// Work color vectors
CVECTOR outCol, outCol1, outCol2 = { 0,0,0,0 };
// Find local color from three normal vectors and perform depth cueing.
// Could be replaced with one call with NormalColorDpq3()
NormalColorDpq(&modelCube.n[ modelCube_index[t+0] ], &modelCube.c[i+0], p, &outCol);
NormalColorDpq(&modelCube.n[ modelCube_index[t+2] ], &modelCube.c[i+2], p, &outCol1);
NormalColorDpq(&modelCube.n[ modelCube_index[t+1] ], &modelCube.c[i+1], p, &outCol2);
// Set vertex colors
setRGB0(poly, outCol.r, outCol.g , outCol.b);
setRGB1(poly, outCol1.r, outCol1.g, outCol1.b);
setRGB2(poly, outCol2.r, outCol2.g, outCol2.b);
// Sort the primitive into the OT
OTz /= 3;
if ((OTz > 0) && (OTz < OTLEN))
AddPrim(&ot[db][OTz-2], poly);
nextpri += sizeof(POLY_G3);
t+=3;
}
// Find and apply light rotation matrix
//~ // Find rotmat from light angles
RotMatrix_gte(&lgtang, &rotlgt);
// Find rotmat from cube angles
RotMatrix_gte(&Rotate, &rotcube);
// RotMatrix cube * RotMatrix light
MulMatrix0(&rotcube, &rotlgt, &rotlgt);
// Light Matrix * RotMatrix light
MulMatrix0(&lgtmat, &rotlgt, &light);
// Set new light matrix
SetLightMatrix(&light);
// Convert and set the matrices
// Find Rotation matrix from object's angles
RotMatrix(&Rotate, &Matrix);
// Find Scale matrix from object's angles
ScaleMatrix(&Matrix, &Scale);
// Find Translation matrix from object's angles
TransMatrix(&Matrix, &Trans);
// Set GTE's rotation matrix
SetRotMatrix(&Matrix);
// Set GTE's Translation matrix
SetTransMatrix(&Matrix);
// Draw static cube
t=0;
for (i = 0; i < (modelCube1.len*3); i += 3) {
poly1 = (POLY_G3 *)nextpri;
SetPolyG3(poly1);
OTz = RotTransPers(&modelCube1_mesh[modelCube1_index[t]] , (long*)&poly1->x0, &p, &Flag);
OTz += RotTransPers(&modelCube1_mesh[modelCube1_index[t+2]], (long*)&poly1->x1, &p, &Flag);
OTz += RotTransPers(&modelCube1_mesh[modelCube1_index[t+1]], (long*)&poly1->x2, &p, &Flag);
CVECTOR outCol = { 0,0,0,0 };
CVECTOR outCol1 = { 0,0,0,0 };
CVECTOR outCol2 = { 0,0,0,0 };
NormalColorDpq(&modelCube1.n[ modelCube1_index[t+0] ], &modelCube1.c[i+0], p, &outCol);
NormalColorDpq(&modelCube1.n[ modelCube1_index[t+2] ], &modelCube1.c[i+2], p, &outCol1);
NormalColorDpq(&modelCube1.n[ modelCube1_index[t+1] ], &modelCube1.c[i+1], p, &outCol2);
setRGB0(poly1, outCol.r, outCol.g , outCol.b);
setRGB1(poly1, outCol1.r, outCol1.g, outCol1.b);
setRGB2(poly1, outCol2.r, outCol2.g, outCol2.b);
OTz /= 3;
if ((OTz > 0) && (OTz < OTLEN))
AddPrim(&ot[db][OTz-2], poly1);
nextpri += sizeof(POLY_G3);
t+=3;
}
// See l.216
RotMatrix_gte(&lgtang, &rotlgt);
RotMatrix_gte(&Rotate1, &rotcube);
MulMatrix0(&rotcube, &rotlgt, &rotlgt);
MulMatrix0(&lgtmat, &rotlgt, &light);
SetLightMatrix(&light);
// See l.227
RotMatrix(&Rotate1, &Matrix1);
ScaleMatrix(&Matrix1, &Scale1);
TransMatrix(&Matrix1, &Trans1);
SetRotMatrix(&Matrix1);
SetTransMatrix(&Matrix1);
FntPrint("Hello lightsources !\n");
FntFlush(-1);
display();
}
return 0;
}

8
hello_multivag/Makefile Normal file
View File

@ -0,0 +1,8 @@
TARGET = hello_multivag
SRCS = hello_multivag.c \
../VAG/hello.vag \
../VAG/poly.vag \
include ../common.mk
include ../thirdparty/nugget/common.mk \

View File

@ -0,0 +1,320 @@
// VAGDEMO2020 by Schnappy
// December 2020
// Based on VAGDEMO_FIXED by Yagotzirck
// Based on VAGDEMO by Shadow
// based on psyq/addons/sound/TUTO3.C
//
//
// Load two VAG file to SPU sound buffer and play them back alternatively or simultaneously.
//
// WAV creation: use ffmpeg to create a 16-bit ADPCM mono WAV file - change -ar to reduce filesize (and quality)
// $ ffmpeg -i input.mp3 -acodec pcm_s16le -ac 1 -ar 44100 output.wav
//
// WAV to VAG convertion using WAV2VAG : https://github.com/ColdSauce/psxsdk/blob/master/tools/wav2vag.c
// change -freq according to the -ar setting above
// $ wav2vag input.wav output.vag -sraw16 -freq=44100 (-L)
//
// Alternatively, you can use PsyQ VAGEDIT.EXE to change the sampling frequency of an existing VAG file.
//
// Docs : see libformat47.pdf p.209
// libover47.pdf, p.271
// libref47.pdf, p.980
// URLS : http://psx.arthus.net/code/VAG/
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
// Sound system
#include <libsnd.h>
#include <libspu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define MARGINX 0 // margins for text display
#define MARGINY 32
#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
// Sound stuff
#define MALLOC_MAX 3 // Max number of time we can call SpuMalloc
//~ // convert Little endian to Big endian
#define SWAP_ENDIAN32(x) (((x)>>24) | (((x)>>8) & 0xFF00) | (((x)<<8) & 0x00FF0000) | ((x)<<24))
typedef struct VAGheader{ // All the values in this header must be big endian
char id[4]; // VAGp 4 bytes -> 1 char * 4
unsigned int version; // 4 bytes
unsigned int reserved; // 4 bytes
unsigned int dataSize; // (in bytes) 4 bytes
unsigned int samplingFrequency;// 4 bytes
char reserved2[12]; // 12 bytes -> 1 char * 12
char name[16]; // 16 bytes -> 1 char * 16
// Waveform data after that
}VAGhdr;
SpuCommonAttr commonAttributes; // structure for changing common voice attributes
SpuVoiceAttr voiceAttributes ; // structure for changing individual voice attributes
u_long hello_spu_address; // address allocated in memory for first sound file
u_long poly_spu_address; // address allocated in memory for second sound file
// DEBUG : these allow printing values for debugging
u_long hello_spu_start_address;
u_long hello_get_start_addr;
u_long hello_transSize;
u_long poly_spu_start_address;
u_long poly_get_start_addr;
u_long poly_transSize;
#define HELLO SPU_0CH // Play first vag on channel 0
#define POLY SPU_2CH // Play second vag on channel 2
// Memory management table ; allow MALLOC_MAX calls to SpuMalloc() - ibref47.pdf p.1044
char spu_malloc_rec[SPU_MALLOC_RECSIZ * (2 + MALLOC_MAX+1)];
// VAG files
// We're using GrumpyCoder's Nugget wrapper to compile the code with a modern GCC : https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/psyq
// To include binary files in the exe, add your VAG files to the SRCS variable in Makefile
// and in common.mk, add this rule to include *.vag files :
//
//~ %.o: %.vag
//~ $(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O elf32-tradlittlemips -B mips $< $@
// hello.vag - 44100 Khz
extern unsigned char _binary____VAG_hello_vag_start[]; // filename must begin with _binary____ followed by the full path, with . and / replaced, and then suffixed with _ and end with _start[]; or end[];
extern unsigned char _binary____VAG_hello_vag_end[]; // https://discord.com/channels/642647820683444236/663664210525290507/780866265077383189
// poly.vag - 44100 Khz
extern unsigned char _binary____VAG_poly_vag_start[];
extern unsigned char _binary____VAG_poly_vag_end[];
void initGraph(void)
{
ResetGraph(0);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(8, 60, 304, 200, 0, 500 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
db = !db;
}
// Audio initialisation & functions
void initSnd(void){
SpuInitMalloc(MALLOC_MAX, spu_malloc_rec); // Maximum number of blocks, mem. management table address.
commonAttributes.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR); // Mask which attributes to set
commonAttributes.mvol.left = 0x3fff; // Master volume left
commonAttributes.mvol.right = 0x3fff; // see libref47.pdf, p.1058
SpuSetCommonAttr(&commonAttributes); // set attributes
SpuSetIRQ(SPU_OFF);
}
u_long sendVAGtoRAM(unsigned int VAG_data_size, unsigned char *VAG_data){
u_long size;
SpuSetTransferMode(SpuTransByDMA); // DMA transfer; can do other processing during transfer
size = SpuWrite (VAG_data + sizeof(VAGhdr), VAG_data_size); // transfer VAG_data_size bytes from VAG_data address to sound buffer
SpuIsTransferCompleted (SPU_TRANSFER_WAIT); // Checks whether transfer is completed and waits for completion
return size;
}
void setVoiceAttr(unsigned int pitch, long channel, unsigned long soundAddr ){
voiceAttributes.mask= //~ Attributes (bit string, 1 bit per attribute)
(
SPU_VOICE_VOLL |
SPU_VOICE_VOLR |
SPU_VOICE_PITCH |
SPU_VOICE_WDSA |
SPU_VOICE_ADSR_AMODE |
SPU_VOICE_ADSR_SMODE |
SPU_VOICE_ADSR_RMODE |
SPU_VOICE_ADSR_AR |
SPU_VOICE_ADSR_DR |
SPU_VOICE_ADSR_SR |
SPU_VOICE_ADSR_RR |
SPU_VOICE_ADSR_SL
);
voiceAttributes.voice = channel; //~ Voice (low 24 bits are a bit string, 1 bit per voice )
voiceAttributes.volume.left = 0x1000; //~ Volume
voiceAttributes.volume.right = 0x1000; //~ Volume
voiceAttributes.pitch = pitch; //~ Interval (set pitch)
voiceAttributes.addr = soundAddr; //~ Waveform data start address
voiceAttributes.a_mode = SPU_VOICE_LINEARIncN; //~ Attack rate mode = Linear Increase - see libref47.pdf p.1091
voiceAttributes.s_mode = SPU_VOICE_LINEARIncN; //~ Sustain rate mode = Linear Increase
voiceAttributes.r_mode = SPU_VOICE_LINEARDecN; //~ Release rate mode = Linear Decrease
voiceAttributes.ar = 0x0; //~ Attack rate
voiceAttributes.dr = 0x0; //~ Decay rate
voiceAttributes.rr = 0x0; //~ Release rate
voiceAttributes.sr = 0x0; //~ Sustain rate
voiceAttributes.sl = 0xf; //~ Sustain level
SpuSetVoiceAttr(&voiceAttributes); // set attributes
}
void playSFX(unsigned long fx){
SpuSetKey(SpuOn, fx);
}
int main(void)
{
short counter = 0;
const VAGhdr * HellofileHeader = (VAGhdr *) _binary____VAG_hello_vag_start; // get header of first VAG file
const VAGhdr * PolyfileHeader = (VAGhdr *) _binary____VAG_poly_vag_start; // get header of second VAG file
// From libover47.pdf :
// The sampling frequency of the original audio file can be used to determine the pitch
// at which to play the VAG. pitch = (sampling frequency << 12)/44100L
// Ex: 44.1kHz=0x1000 22.05kHz=0x800 etc
unsigned int Hellopitch = (SWAP_ENDIAN32(HellofileHeader->samplingFrequency) << 12) / 44100L;
unsigned int Polypitch = (SWAP_ENDIAN32(PolyfileHeader->samplingFrequency) << 12) / 44100L;
SpuInit(); // Initialize SPU. Called only once.
initSnd();
// First VAG
hello_spu_address = SpuMalloc(SWAP_ENDIAN32(HellofileHeader->dataSize)); // Allocate an area of dataSize bytes in the sound buffer.
hello_spu_start_address = SpuSetTransferStartAddr(hello_spu_address); // Sets a starting address in the sound buffer
hello_get_start_addr = SpuGetTransferStartAddr(); // SpuGetTransferStartAddr() returns current sound buffer transfer start address.
hello_transSize = sendVAGtoRAM(SWAP_ENDIAN32(HellofileHeader->dataSize), _binary____VAG_hello_vag_start);
// First VAG
poly_spu_address = SpuMalloc(SWAP_ENDIAN32(PolyfileHeader->dataSize)); // Allocate an area of dataSize bytes in the sound buffer.
poly_spu_start_address = SpuSetTransferStartAddr(poly_spu_address); // Sets a starting address in the sound buffer
poly_get_start_addr = SpuGetTransferStartAddr(); // SpuGetTransferStartAddr() returns current sound buffer transfer start address.
poly_transSize = sendVAGtoRAM(SWAP_ENDIAN32(PolyfileHeader->dataSize), _binary____VAG_poly_vag_start);
// set VAG to channel
setVoiceAttr(Hellopitch, HELLO, hello_spu_address); // SPU_0CH == hello
setVoiceAttr(Polypitch, POLY, poly_spu_address); // SPU_2CH == poly
initGraph();
while (1)
{
if(!counter){
playSFX(HELLO); // Play first VAG
counter = 240;
}
if(counter == 160){
playSFX(POLY); // Play second VAG
}
if(counter == 80){
playSFX(HELLO|POLY); // Play both VAGs simultaneously
}
FntPrint("First VAG:");
FntPrint("\nPitch : %08x-%dKhz", Hellopitch, (SWAP_ENDIAN32(HellofileHeader->samplingFrequency)) );
FntPrint("\nSet Start addr : %08x", hello_spu_address);
FntPrint("\nReturn start addr : %08x", hello_spu_start_address);
FntPrint("\nGet Start addr : %08x", hello_get_start_addr);
FntPrint("\nSend size : %08x", SWAP_ENDIAN32(HellofileHeader->dataSize));
FntPrint("\nReturn size : %08x\n", hello_transSize);
FntPrint("\nSecond VAG:");
FntPrint("\nPitch : %08x-%dKhz", Polypitch, (SWAP_ENDIAN32(HellofileHeader->samplingFrequency)) );
FntPrint("\nSet Start addr : %08x", poly_spu_address);
FntPrint("\nReturn start addr : %08x", poly_spu_start_address);
FntPrint("\nGet Start addr : %08x", poly_get_start_addr);
FntPrint("\nSend size : %08x", SWAP_ENDIAN32(PolyfileHeader->dataSize));
FntPrint("\nReturn size : %08x\n", poly_transSize);
FntPrint("\nCounter : %d\n", counter);
FntFlush(-1);
counter --;
display();
}
return 0;
}

6
hello_pad/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_pad
SRCS = hello_pad.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

213
hello_pad/hello_pad.c Normal file
View File

@ -0,0 +1,213 @@
// hello_pad example
//
// We're using libetc PadInit() and PadRead() that only supports the 16 buttons pad
// but doesn't need the libpad lib. It's fine for prototyping and simple stuff.
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define MARGINX 32 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 2 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
void init(void)
{
ResetGraph(0);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main(void)
{
TILE * PADL; // Tile primitives
TILE * TRIGGERL;
TILE * PADR;
TILE * TRIGGERR;
TILE * START, * SELECT;
int pad = 0;
init();
PadInit(0); // Initialize pad. Mode is always 0
while (1)
{
ClearOTagR(ot[db], OTLEN);
// D-cross
PADL = (TILE *)nextpri;
setTile(PADL);
setRGB0(PADL, 0, 0, 255);
setXY0(PADL, CENTERX - 80, CENTERY);
setWH(PADL, 24, 24);
addPrim(ot[db], PADL);
nextpri += sizeof(TILE);
// L1+L2
TRIGGERL = (TILE *)nextpri;
setTile(TRIGGERL);
setRGB0(TRIGGERL, 255, 0, 0);
setXY0(TRIGGERL, CENTERX - 80, CENTERY - 80);
setWH(TRIGGERL, 24, 24);
addPrim(ot[db], TRIGGERL);
nextpri += sizeof(TILE);
// /\, X, O, []
PADR = (TILE *)nextpri;
setTile(PADR);
setRGB0(PADR, 0, 255, 0);
setXY0(PADR, CENTERX + 50, CENTERY);
setWH(PADR, 24, 24);
addPrim(ot[db], PADR);
nextpri += sizeof(TILE);
// R1+R2
TRIGGERR = (TILE *)nextpri;
setTile(TRIGGERR);
setRGB0(TRIGGERR, 255, 0, 255);
setXY0(TRIGGERR, CENTERX + 50, CENTERY -80);
setWH(TRIGGERR, 24, 24);
addPrim(ot[db], TRIGGERR);
nextpri += sizeof(TILE);
// START + SELECT
START = (TILE *)nextpri;
setTile(START);
setRGB0(START, 240, 240, 240);
setXY0(START, CENTERX - 16, CENTERY - 36);
setWH(START, 24, 24);
addPrim(ot[db], START);
nextpri += sizeof(TILE);
// Pad stuff
pad = PadRead(0); // Read pads input. id is unused, always 0.
// PadRead() returns a 32 bit value, where input from pad 1 is stored in the low 2 bytes and input from pad 2 is stored in the high 2 bytes. (https://matiaslavik.wordpress.com/2015/02/13/diving-into-psx-development/)
// D-pad
if(pad & PADLup) {PADL->y0 = CENTERY - 16;} // 🡩 // To access pad 2, use ( pad >> 16 & PADLup)...
if(pad & PADLdown) {PADL->y0 = CENTERY + 16;} // 🡫
if(pad & PADLright){PADL->x0 = CENTERX - 64;} // 🡪
if(pad & PADLleft) {PADL->x0 = CENTERX - 96;} // 🡨
// Buttons
if(pad & PADRup) {PADR->y0 = CENTERY - 16;} // △
if(pad & PADRdown) {PADR->y0 = CENTERY + 16;} //
if(pad & PADRright){PADR->x0 = CENTERX + 66;} // ⭘
if(pad & PADRleft) {PADR->x0 = CENTERX + 34;} // ⬜
// Shoulder buttons
if(pad & PADL1){TRIGGERL->y0 = CENTERY - 64;} // L1
if(pad & PADL2){TRIGGERL->y0 = CENTERY - 96;} // L2
if(pad & PADR1){TRIGGERR->y0 = CENTERY - 64;} // R1
if(pad & PADR2){TRIGGERR->y0 = CENTERY - 96;} // R2
// Start & Select
if(pad & PADstart){START->w = 32; START->h = 32;START->x0 -= 4;START->y0 -= 4;} // START
if(pad & PADselect){START->r0 = 0;} // SELECT
FntPrint("Hello Pad!");
FntFlush(-1);
display();
}
return 0;
}

6
hello_poly/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_poly
SRCS = hello_poly.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

197
hello_poly/hello_poly.c Normal file
View File

@ -0,0 +1,197 @@
// With help from Nicolas Noble, Jaby smoll Seamonstah
// Based on Lameguy64's tutorial series : http://lameguy64.net/svn/pstutorials/chapter1/2-graphics.html
//
// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :
//
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#include <libapi.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320 // Screen width
#define SCREENYRES 240 // Screen height
#define CENTERX SCREENXRES/2 // Center of screen on x
#define CENTERY SCREENYRES/2 // Center of screen on y
#define MARGINX 0 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 7 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
MATRIX identity(int num) // generate num x num matrix
{
int row, col;
MATRIX matrix;
for (row = 0; row < num; row++)
{
for (col = 0; col < num; col++)
{
if (row == col)
matrix.m[row][col] = 4096;
else
matrix.m[row][col] = 0;
}
}
return matrix;
}
void init(void)
{
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX,CENTERY);
SetGeomScreen(CENTERX);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main(void)
{
MATRIX IDMATRIX = identity(3); // Generate 3x3 identity matrix
POLY_F4 *poly = {0}; // pointer to a POLY_F4
SVECTOR RotVector = {0, 0, 0}; // Initialize rotation vector {x, y, z}
VECTOR MovVector = {0, 0, CENTERX, 0}; // Initialize translation vector {x, y, z}
VECTOR ScaleVector ={ONE, ONE, ONE}; // ONE is define as 4096 in libgte.h
SVECTOR VertPos[4] = { // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg
{-32, -32, 1 }, // Vert 1
{-32, 32, 1 }, // Vert 2
{ 32, -32, 1 }, // Vert 3
{ 32, 32, 1 } // Vert 4
};
MATRIX PolyMatrix = IDMATRIX;
long polydepth;
long polyflag;
long OTz;
init();
while (1)
{
ClearOTagR(ot[db], OTLEN);
poly = (POLY_F4 *)nextpri; // Set poly to point to the address of the next primitiv in the buffer
// Set transform matrices for this polygon
RotMatrix(&RotVector, &PolyMatrix); // Apply rotation matrix
TransMatrix(&PolyMatrix, &MovVector);
ScaleMatrix(&PolyMatrix, &ScaleVector); // Apply translation matrix
SetRotMatrix(&PolyMatrix); // Set default rotation matrix
SetTransMatrix(&PolyMatrix); // Set default transformation matrix
setPolyF4(poly); // Initialize poly as a POLY_F4
setRGB0(poly, 255, 0, 255); // Set poly color
// RotTransPers
//~ OTz = RotTransPers(&VertPos[0], (long*)&poly->x0, &polydepth, &polyflag);
//~ RotTransPers(&VertPos[1], (long*)&poly->x1, &polydepth, &polyflag);
//~ RotTransPers(&VertPos[2], (long*)&poly->x2, &polydepth, &polyflag);
//~ RotTransPers(&VertPos[3], (long*)&poly->x3, &polydepth, &polyflag);
// RotTransPers4 equivalent
OTz = RotTransPers4(
&VertPos[0], &VertPos[1], &VertPos[2], &VertPos[3],
(long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,
&polydepth,
&polyflag
); // Perform coordinate and perspective transformation for 4 vertices
RotVector.vy += 4;
RotVector.vz += 4; // Apply rotation on Z-axis. On PSX, the Z-axis is pointing away from the screen.
addPrim(ot[db], poly); // add poly to the Ordering table
nextpri += sizeof(POLY_F4); // increment nextpri address with size of a POLY_F4 struct
FntPrint("Hello Poly !");
FntFlush(-1);
display();
}
return 0;
}

7
hello_poly_ft/Makefile Normal file
View File

@ -0,0 +1,7 @@
TARGET = hello_poly_ft
SRCS = hello_poly_ft.c \
../TIM/bousai.tim \
include ../common.mk
include ../thirdparty/nugget/common.mk \

View File

@ -0,0 +1,231 @@
// With help from Nicolas Noble, Jaby smoll Seamonstah
// Based on Lameguy64's tutorial series : http://lameguy64.net/svn/pstutorials/chapter1/2-graphics.html
//
// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :
//
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320 // Screen width
#define SCREENYRES 240 // Screen height
#define CENTERX SCREENXRES/2 // Center of screen on x
#define CENTERY SCREENYRES/2 // Center of screen on y
#define MARGINX 32 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 5 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
// 16bpp TIM
extern unsigned long _binary____TIM_bousai_tim_start[];
extern unsigned long _binary____TIM_bousai_tim_end[];
extern unsigned long _binary____TIM_bousai_tim_length;
TIM_IMAGE bousai;
MATRIX identity(int num) // generate num x num matrix
{
int row, col;
MATRIX matrix;
for (row = 0; row < num; row++)
{
for (col = 0; col < num; col++)
{
if (row == col)
matrix.m[row][col] = 4096;
else
matrix.m[row][col] = 0;
}
}
return matrix;
}
void LoadTexture(u_long * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous
OpenTIM(tim); // Open the tim binary data, feed it the address of the data in memory
ReadTIM(tparam); // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure
LoadImage(tparam->prect, tparam->paddr); // Transfer the data from memory to VRAM at position prect.x, prect.y
DrawSync(0); // Wait for the drawing to end
if (tparam->mode & 0x8){ // check 4th bit // If 4th bit == 1, TIM has a CLUT
LoadImage(tparam->crect, tparam->caddr); // Load it to VRAM at position crect.x, crect.y
DrawSync(0); // Wait for drawing to end
}
}
void init(void)
{
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX,CENTERY);
SetGeomScreen(CENTERX);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 128, 128, 128);
setRGB0(&draw[1], 128, 128, 128);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main(void)
{
MATRIX IDMATRIX = identity(3); // Generate 3x3 identity matrix
POLY_FT4 *poly = {0}; // pointer to a POLY_G4
SVECTOR RotVector = {0, 0, 0}; // Initialize rotation vector {x, y, z}
VECTOR MovVector = {0, 0, CENTERX/2, 0}; // Initialize translation vector {x, y, z, pad}
VECTOR ScaleVector = {ONE, ONE, ONE}; // ONE is define as 4096 in libgte.h
SVECTOR VertPos[4] = { // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg
{-32, -32, 1 }, // Vert 1
{-32, 32, 1 }, // Vert 2
{ 32, -32, 1 }, // Vert 3
{ 32, 32, 1 } // Vert 4
};
MATRIX PolyMatrix = IDMATRIX;
long polydepth;
long polyflag;
int ping = 0;
init();
LoadTexture(_binary____TIM_bousai_tim_start, &bousai);
while (1)
{
ClearOTagR(ot[db], OTLEN);
poly = (POLY_FT4 *)nextpri; // Set poly to point to the address of the next primitiv in the buffer
// Set transform matrices for this polygon
RotMatrix(&RotVector, &PolyMatrix); // Apply rotation matrix
TransMatrix(&PolyMatrix, &MovVector); // Apply translation matrix
ScaleMatrix(&PolyMatrix, &ScaleVector); // Apply scale matrix
SetRotMatrix(&PolyMatrix); // Set default rotation matrix
SetTransMatrix(&PolyMatrix); // Set default transformation matrix
setPolyFT4(poly); // Initialize poly as a POLY_F4
poly->tpage = getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y); // Get Tpage coordinates from the TIM_IMAGE mode and prect members.
setRGB0(poly, 128, 128, 128); // Set poly color (neutra here)
RotTransPers4(
&VertPos[0], &VertPos[1], &VertPos[2], &VertPos[3],
(long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,
&polydepth,
&polyflag
); // Perform coordinate and perspective transformation for 4 vertices
setUV4(poly, 0, 0, 0, 144, 144, 0, 144, 144); // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right
// Let's have some fun on the Z axis
if(!ping){
if (MovVector.vz < CENTERX){ // While Poly position on Z axis is < 160, push it
MovVector.vz += 1; // Push on Z axis
} else {
ping = !ping; // Switch ping value
}
}
if(ping){
if (MovVector.vz > CENTERX/2){ // While Poly position on Z axis is > 80, pull it
MovVector.vz -= 1; // Pull on Z axis
} else {
ping = !ping; // Switch ping value
}
}
addPrim(ot[db], poly); // add poly to the Ordering table
nextpri += sizeof(POLY_FT4); // increment nextpri address with size of a POLY_F4 struct
FntPrint("Hello textured poly !");
FntFlush(-1);
display();
}
return 0;
}

6
hello_poly_fun/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_poly_fun
SRCS = hello_poly_fun.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

View File

@ -0,0 +1,618 @@
// Having fun with polygons, matrices and vectors
// Credits : Schnappy
//With great help from Jaby smoll Seamonstah, Nicolas Noble, NDR008, paul, sickle on https://discord.com/invite/Zd82yXvs
// 11/2020
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#include <kernel.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SPIN 16 // Rotation speed increment
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define MARGINX 10 // margins for text display
#define MARGINY 4
#define FONTSIZE 8 * 7 // Text Field Height
#define OTLEN 16 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
CVECTOR BgColor[3] = {20, 20, 20};
struct polygon
{
POLY_F4 * poly_f4;
CVECTOR color;
short width;
short height;
//~ VECTOR PosV_L; // Not used anymore
SVECTOR RotV_L;
VECTOR TransV_L;
VECTOR ScaleV_L;
SVECTOR PivotV_L;
SVECTOR Verts[4];
MATRIX Matrix;
long depth;
long flag;
short rotSpeed;
int otz;
};
void init(void)
{
ResetGraph(0);
// Initialize and setup the GTE : Not needed ?
InitGeom();
SetGeomOffset(CENTERX,CENTERY);
SetGeomScreen(CENTERX);
PadInit(0);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], BgColor->r, BgColor->g, BgColor->b);
setRGB0(&draw[1], BgColor->r, BgColor->g, BgColor->b);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
void pivotPoint(SVECTOR VertPos[3],short width,short height, SVECTOR pivot){
// Not very efficient I think
VertPos[0].vx = -pivot.vx;
VertPos[0].vy = -pivot.vy;
VertPos[0].vz = 1;
VertPos[1].vx = width - pivot.vx;
VertPos[1].vy = -pivot.vy;
VertPos[1].vz = 1;
VertPos[2].vx = -pivot.vx;
VertPos[2].vy = height-pivot.vy;
VertPos[2].vz = 1;
VertPos[3].vx = width - pivot.vx;
VertPos[3].vy = height - pivot.vy;
VertPos[3].vz = 1;
}
MATRIX identity(int num)
{
int row, col;
MATRIX matrix;
for (row = 0; row < num; row++)
{
for (col = 0; col < num; col++)
{
if (row == col)
matrix.m[row][col] = 4096;
else
matrix.m[row][col] = 0;
}
}
return matrix;
}
int main(void)
{
MATRIX IDMATRIX = identity(3);
u_short BtnTimer = 0; // Timer to limit pad input rate
u_short polyCount = 1; // current polygon index
int otz; // z-index
struct polygon *CurrentPoly; // points to the address of selected polygon
// White cursor : shows which polygon is selected
struct polygon cursorS = {
cursorS.poly_f4,
{255, 255, 255}, // color
30, 30, // width, height
{0,0,0}, // RotV_L
{0,0,0, 0}, // TransV_L
{4096,4096,4096}, // ScaleV_L
{1,1,1}, // PivotV
{ // Verts[4]
{-1, -1, 1},
{ 1, -1, 1},
{-1, 1, 1},
{ 1, 1, 1}
},
IDMATRIX // Matrix
};
//Red
struct polygon polyS = {
polyS.poly_f4,
{255, 0, 0}, // color
30, 30, // width, height
{0,0,0}, // RotV_L
{-48, -30, 0, 0}, // TransV_L
{4096,4096,4096}, // ScaleV_L
{15,15,1}, // PivotV
{ // Verts[4]
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
},
IDMATRIX, // Matrix
0,0, // depth, flag
8, // rotSpeed
1 // z-index
};
//Yellow
struct polygon poly1S = {
poly1S.poly_f4,
{255, 187, 0}, // color
28, 28, // width, height
{0,0,0}, // RotV_L
{-20, 10, 0, 0}, // TransV_L
{4096,4096,4096}, // ScaleV_L
{4,4,1}, // PivotV
{ // Verts[4]
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
},
IDMATRIX, // Matrix
0,0, // depth, flag
-12, // rotSpeed
2 // z-index
};
//Green
struct polygon poly2S = {
poly2S.poly_f4,
{0, 255, 153}, // color
24, 24, // width, height
{0,0,0}, // RotV_L
{36, -10, 0, 0}, // TransV_L
{4096,4096,4096}, // ScaleV_L
{12,12,1}, // PivotV
{ // Verts[4]
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
},
IDMATRIX, // Matrix
0,0, // depth, flag
-6, // rotSpeed
3 // z-index
};
//Blue
struct polygon poly3S = {
poly3S.poly_f4,
{112, 254, 254}, // color
26, 26, // width, height
{0,0,0}, // RotV_L
{20, 20, 0, 0}, // TransV_L
{4096,4096,4096}, // ScaleV_L
{13,13,1}, // PivotV
{ // Verts[4]
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
},
IDMATRIX, // Matrix
0,0, //depth, flag
256, //rotSpeed
4 // z-index
};
/////
CurrentPoly = &polyS;
pivotPoint(polyS.Verts, polyS.width, polyS.height, polyS.PivotV_L);
pivotPoint(poly1S.Verts, poly1S.width, poly1S.height, poly1S.PivotV_L);
pivotPoint(poly2S.Verts, poly2S.width, poly2S.height, poly2S.PivotV_L);
pivotPoint(poly3S.Verts, poly3S.width, poly3S.height, poly3S.PivotV_L);
init();
while (1)
{
ClearOTagR(ot[db], OTLEN);
cursorS.poly_f4 = (POLY_F4 *)nextpri;
RotMatrix(&cursorS.RotV_L , &cursorS.Matrix);
TransMatrix(&cursorS.Matrix, &CurrentPoly->TransV_L);
SetRotMatrix(&cursorS.Matrix);
SetTransMatrix(&cursorS.Matrix);
setPolyF4(cursorS.poly_f4);
setRGB0(cursorS.poly_f4,cursorS.color.r,cursorS.color.g,cursorS.color.b);
//~ setXY4(cursorS, MovVector.vx-1, MovVector.vy-1 ,MovVector.vx + 1, MovVector.vy -1,MovVector.vx-1, MovVector.vy+1,MovVector.vx+1, MovVector.vy+1);
RotTransPers4(
&cursorS.Verts[0], &cursorS.Verts[1], &cursorS.Verts[2], &cursorS.Verts[3],
(long*)&cursorS.poly_f4->x0, (long*)&cursorS.poly_f4->x1, (long*)&cursorS.poly_f4->x2, (long*)&cursorS.poly_f4->x3,
&cursorS.depth,
&cursorS.flag
);
addPrim(ot[db], cursorS.poly_f4);
nextpri += sizeof(POLY_F4);
///// Red
polyS.poly_f4 = (POLY_F4 *)nextpri;
polyS.RotV_L.vz += polyS.rotSpeed;
RotMatrix(&polyS.RotV_L, &polyS.Matrix);
TransMatrix(&polyS.Matrix, &polyS.TransV_L);
ScaleMatrix(&polyS.Matrix, &polyS.ScaleV_L);
SetRotMatrix(&polyS.Matrix);
SetTransMatrix(&polyS.Matrix);
setPolyF4(polyS.poly_f4);
setRGB0(polyS.poly_f4, polyS.color.r,polyS.color.g,polyS.color.b);
RotTransPers4(
&polyS.Verts[0], &polyS.Verts[1], &polyS.Verts[2], &polyS.Verts[3],
(long*)&polyS.poly_f4->x0, (long*)&polyS.poly_f4->x1, (long*)&polyS.poly_f4->x2, (long*)&polyS.poly_f4->x3,
&polyS.depth,
&polyS.flag
);
addPrim(ot[db]+polyS.otz, polyS.poly_f4);
nextpri += sizeof(POLY_F4);
///// Yellow
poly1S.poly_f4 = (POLY_F4 *)nextpri;
poly1S.RotV_L.vz += poly1S.rotSpeed;
RotMatrix(&poly1S.RotV_L, &poly1S.Matrix);
TransMatrix(&poly1S.Matrix, &poly1S.TransV_L);
ScaleMatrix(&poly1S.Matrix, &poly1S.ScaleV_L);
SetRotMatrix(&poly1S.Matrix);
SetTransMatrix(&poly1S.Matrix);
setPolyF4(poly1S.poly_f4);
setRGB0(poly1S.poly_f4, poly1S.color.r,poly1S.color.g,poly1S.color.b);
RotTransPers4(
&poly1S.Verts[0], &poly1S.Verts[1], &poly1S.Verts[2], &poly1S.Verts[3],
(long*)&poly1S.poly_f4->x0, (long*)&poly1S.poly_f4->x1, (long*)&poly1S.poly_f4->x2, (long*)&poly1S.poly_f4->x3,
&poly1S.depth,
&poly1S.flag
);
addPrim(ot[db]+poly1S.otz, poly1S.poly_f4);
nextpri += sizeof(POLY_F4);
///// Green
poly2S.poly_f4 = (POLY_F4 *)nextpri;
poly2S.RotV_L.vz += poly2S.rotSpeed;
RotMatrix(&poly2S.RotV_L, &poly2S.Matrix);
TransMatrix(&poly2S.Matrix, &poly2S.TransV_L);
ScaleMatrix(&poly2S.Matrix, &poly2S.ScaleV_L);
SetRotMatrix(&poly2S.Matrix);
SetTransMatrix(&poly2S.Matrix);
setPolyF4(poly2S.poly_f4);
setRGB0(poly2S.poly_f4, poly2S.color.r,poly2S.color.g,poly2S.color.b);
RotTransPers4(
&poly2S.Verts[0], &poly2S.Verts[1], &poly2S.Verts[2], &poly2S.Verts[3],
(long*)&poly2S.poly_f4->x0, (long*)&poly2S.poly_f4->x1, (long*)&poly2S.poly_f4->x2, (long*)&poly2S.poly_f4->x3,
&poly2S.depth,
&poly2S.flag
);
addPrim(ot[db]+poly2S.otz, poly2S.poly_f4);
nextpri += sizeof(POLY_F4);
///// Blue
poly3S.poly_f4 = (POLY_F4 *)nextpri;
poly3S.RotV_L.vz += poly3S.rotSpeed;
RotMatrix(&poly3S.RotV_L, &poly3S.Matrix);
TransMatrix(&poly3S.Matrix, &poly3S.TransV_L);
ScaleMatrix(&poly3S.Matrix, &poly3S.ScaleV_L);
SetRotMatrix(&poly3S.Matrix);
SetTransMatrix(&poly3S.Matrix);
setPolyF4(poly3S.poly_f4);
setRGB0(poly3S.poly_f4, poly3S.color.r,poly3S.color.g,poly3S.color.b);
RotTransPers4(
&poly3S.Verts[0], &poly3S.Verts[1], &poly3S.Verts[2], &poly3S.Verts[3],
(long*)&poly3S.poly_f4->x0, (long*)&poly3S.poly_f4->x1, (long*)&poly3S.poly_f4->x2, (long*)&poly3S.poly_f4->x3,
&poly3S.depth,
&poly3S.flag
);
addPrim(ot[db]+poly3S.otz, poly3S.poly_f4);
nextpri += sizeof(POLY_F4);
// Pad stuff
int pad = PadRead(0); // init pad
// Right D-pad
if(pad & PADRup){
if (CurrentPoly->PivotV_L.vy >= 0){
CurrentPoly->PivotV_L.vy -= 1;
pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);
}
else {
CurrentPoly->PivotV_L.vy = CurrentPoly->PivotV_L.vy;
}
};
if(pad & PADRdown){
if (CurrentPoly->PivotV_L.vy <= CurrentPoly->height ){
CurrentPoly->PivotV_L.vy += 1;
pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);
}
else {
CurrentPoly->PivotV_L.vy = CurrentPoly->PivotV_L.vy;
}
};
if(pad & PADRleft){
if (CurrentPoly->PivotV_L.vx >= 0){
CurrentPoly->PivotV_L.vx -= 1;
pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);
}
else {
CurrentPoly->PivotV_L.vx = CurrentPoly->PivotV_L.vx;
}
};
if(pad & PADRright){
if (CurrentPoly->PivotV_L.vx <= CurrentPoly->width ){
CurrentPoly->PivotV_L.vx += 1;
pivotPoint(CurrentPoly->Verts, CurrentPoly->width, CurrentPoly->height, CurrentPoly->PivotV_L);
}
else {
CurrentPoly->PivotV_L.vx = CurrentPoly->PivotV_L.vx;
}
};
// R1, R2, L2, L2
if(pad & PADR1){
if(BtnTimer == 0){
if (polyCount < 4){
CurrentPoly -= 1;
BtnTimer = 10;
polyCount++;
}
else {
CurrentPoly = &polyS + 1;
polyCount = 0;
}
}
}
if(pad & PADR2){
if(BtnTimer == 0){
if(CurrentPoly->otz < 5 ){
CurrentPoly->otz += 1;
BtnTimer = 10;
} else {
CurrentPoly->otz = 1;
BtnTimer = 10;
}
}
}
if(pad & PADL1){
if(BtnTimer == 0){
if (CurrentPoly->rotSpeed <= 320){
CurrentPoly->rotSpeed += 8;
}
BtnTimer = 10;
}
}
if(pad & PADL2){
if(BtnTimer == 0){
if (CurrentPoly->rotSpeed >= -320){
CurrentPoly->rotSpeed -= 8;
}
BtnTimer = 10;
}
}
// Left D-Pad
if(pad & PADLup){
if(BtnTimer == 0){
CurrentPoly->TransV_L.vy -= 1;
//~ BtnTimer = 2;
}
}
if(pad & PADLdown){
if(BtnTimer == 0){
CurrentPoly->TransV_L.vy += 1;
//~ BtnTimer = 2;
}
}
if(pad & PADLleft){
if(BtnTimer == 0){
CurrentPoly->TransV_L.vx -= 1;
//~ BtnTimer = 2;
}
}
if(pad & PADLright){
if(BtnTimer == 0){
CurrentPoly->TransV_L.vx += 1;
//~ BtnTimer = 2;
}
}
if(pad & PADstart){
if(BtnTimer == 0){
CurrentPoly->ScaleV_L.vx += 100;
CurrentPoly->ScaleV_L.vy += 100;
//~ CurrentPoly->TransV_L.vz += 1;
}
}
if(pad & PADselect){
if(BtnTimer == 0){
CurrentPoly->ScaleV_L.vx -= 100;
CurrentPoly->ScaleV_L.vy -= 100;
//~ CurrentPoly->TransV_L.vz -= 1;
}
}
// Btn_timer decrement
if(BtnTimer > 0){
BtnTimer -= 1;
}
// Debug stuff
// Display Rotation matrix
//~ FntPrint("Rotmatrix:\n%d %d %d\n%d %d %d\n%d %d %d \n",
//~ Poly1Matrix.m[0][0], Poly1Matrix.m[0][1], Poly1Matrix.m[0][2],
//~ Poly1Matrix.m[1][0], Poly1Matrix.m[1][1], Poly1Matrix.m[1][2],
//~ Poly1Matrix.m[2][0], Poly1Matrix.m[2][1], Poly1Matrix.m[2][2]);
// Display Mem adress and values of verticess
//~ FntPrint("cur:%x\n 0:%x\n 1:%x\n 2:%x\n 3:%x\n", CurrentPoly, &polyS, &poly1S, &poly2S, &poly3S);
//~ FntPrint("timer:%d polyCount:%d speed:%d", BtnTimer, polyCount, CurrentPoly->rotSpeed );
//~ FntPrint("&poly->x0 Addr:%x Value:%d \n&poly->y0 Addr:%x Value:%d \n&poly->x1 Addr:%x Value:%d",
//~ (long)&poly->x0, poly->x0,
//~ (long)&poly->y0, poly->y0,
//~ (long)&poly->x1, poly->x1);
//~ FntPrint("otz : %d\n" , CurrentPoly->rotSpeed);
// On-screen instructions
FntPrint("\
D-Pad:move polygon.\n\
[],X,O,\/\\ : Move pivot point.\n\
L1,L2 : Rotations speed +/-\n\
R1 : select polygon\n\
R2 : change z-index\n\
Start,Select : Scale polygon +/-\
");
FntFlush(-1);
display();
}
return 0;
}

7
hello_poly_gt/Makefile Normal file
View File

@ -0,0 +1,7 @@
TARGET = hello_poly_gt
SRCS = hello_poly_gt.c \
../TIM/bousai.tim \
include ../common.mk
include ../thirdparty/nugget/common.mk \

View File

@ -0,0 +1,215 @@
// With help from Nicolas Noble, Jaby smoll Seamonstah
// Based on Lameguy64's tutorial series : http://lameguy64.net/svn/pstutorials/chapter1/2-graphics.html
//
// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :
//
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320 // Screen width
#define SCREENYRES 240 // Screen height
#define CENTERX SCREENXRES/2 // Center of screen on x
#define CENTERY SCREENYRES/2 // Center of screen on y
#define MARGINX 32 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 5 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
// 16bpp TIM
extern unsigned long _binary____TIM_bousai_tim_start[];
extern unsigned long _binary____TIM_bousai_tim_end[];
extern unsigned long _binary____TIM_bousai_tim_length;
TIM_IMAGE bousai;
MATRIX identity(int num) // generate num x num matrix
{
int row, col;
MATRIX matrix;
for (row = 0; row < num; row++)
{
for (col = 0; col < num; col++)
{
if (row == col)
matrix.m[row][col] = 4096;
else
matrix.m[row][col] = 0;
}
}
return matrix;
}
void LoadTexture(u_long * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous
OpenTIM(tim); // Open the tim binary data, feed it the address of the data in memory
ReadTIM(tparam); // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure
LoadImage(tparam->prect, tparam->paddr); // Transfer the data from memory to VRAM at position prect.x, prect.y
DrawSync(0); // Wait for the drawing to end
if (tparam->mode & 0x8){ // check 4th bit // If 4th bit == 1, TIM has a CLUT
LoadImage(tparam->crect, tparam->caddr); // Load it to VRAM at position crect.x, crect.y
DrawSync(0); // Wait for drawing to end
}
}
void init(void)
{
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX,CENTERY);
SetGeomScreen(CENTERX);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 128, 128, 128);
setRGB0(&draw[1], 128, 128, 128);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main(void)
{
int i;
MATRIX IDMATRIX = identity(3); // Generate 3x3 identity matrix
POLY_GT4 *poly = {0}; // pointer to a POLY_G4
SVECTOR RotVector = {0, 0, 0}; // Initialize rotation vector {x, y, z}
VECTOR MovVector = {0, 0, 120, 0}; // Initialize translation vector {x, y, z}
SVECTOR VertPos[4] = { // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg
{-32, -32, 0 }, // Vert 1
{-32, 32, 0 }, // Vert 2
{ 32, -32, 0 }, // Vert 3
{ 32, 32, 0 } // Vert 4
};
MATRIX PolyMatrix = IDMATRIX;
DR_TPAGE * bousai_tpage;
long polydepth;
long polyflag;
init();
LoadTexture(_binary____TIM_bousai_tim_start, &bousai);
while (1)
{
ClearOTagR(ot[db], OTLEN);
poly = (POLY_GT4 *)nextpri; // Set poly to point to the address of the next primitiv in the buffer
// Set transform matrices for this polygon
RotMatrix(&RotVector, &PolyMatrix); // Apply rotation matrix
TransMatrix(&PolyMatrix, &MovVector); // Apply translation matrix
SetRotMatrix(&PolyMatrix); // Set default rotation matrix
SetTransMatrix(&PolyMatrix); // Set default transformation matrix
setPolyGT4(poly); // Initialize poly as a POLY_F4
poly->tpage = getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y);
setRGB0(poly, 128, 128, 128); // Set vertice 1 color
setRGB1(poly, 255, 0, 0); // Set vertice 2 color
setRGB2(poly, 0, 255, 0); // Set vertice 3 color
setRGB3(poly, 0, 0, 255); // Set vertice 4 color
RotTransPers4(
&VertPos[0], &VertPos[1], &VertPos[2], &VertPos[3],
(long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,
&polydepth,
&polyflag
); // Perform coordinate and perspective transformation for 4 vertices
setUV4(poly, 0, 0, 0, 144, 144, 0, 144, 144); // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right
RotVector.vx += 8; // Apply rotation on Z-axis. On PSX, the Z-axis is pointing away from the screen.
addPrim(ot[db], poly); // add poly to the Ordering table
nextpri += sizeof(POLY_GT4); // increment nextpri address with size of a POLY_F4 struct
FntPrint("Hello textured shaded !");
FntFlush(-1);
display();
}
return 0;
}

View File

@ -0,0 +1,7 @@
TARGET = hello_poly_gt_tw
SRCS = hello_poly_gt_tw.c \
../TIM/bousai.tim \
include ../common.mk
include ../thirdparty/nugget/common.mk \

View File

@ -0,0 +1,234 @@
// With help from Nicolas Noble, Jaby smoll Seamonstah
// Based on Lameguy64's tutorial series : http://lameguy64.net/svn/pstutorials/chapter1/2-graphics.html
//
// From ../psyq/addons/graphics/MESH/RMESH/TUTO0.C :
//
/* PSX screen coordinate system
*
* Z+
* /
* /
* +------X+
* /|
* / |
* / Y+
* eye */
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320 // Screen width
#define SCREENYRES 240 // Screen height
#define CENTERX SCREENXRES/2 // Center of screen on x
#define CENTERY SCREENYRES/2 // Center of screen on y
#define MARGINX 32 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 5 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
// 16bpp TIM
extern unsigned long _binary____TIM_bousai_tim_start[];
extern unsigned long _binary____TIM_bousai_tim_end[];
extern unsigned long _binary____TIM_bousai_tim_length;
TIM_IMAGE bousai;
MATRIX identity(int num) // generate num x num matrix
{
int row, col;
MATRIX matrix;
for (row = 0; row < num; row++)
{
for (col = 0; col < num; col++)
{
if (row == col)
matrix.m[row][col] = 4096;
else
matrix.m[row][col] = 0;
}
}
return matrix;
}
void LoadTexture(u_long * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous
OpenTIM(tim); // Open the tim binary data, feed it the address of the data in memory
ReadTIM(tparam); // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure
LoadImage(tparam->prect, tparam->paddr); // Transfer the data from memory to VRAM at position prect.x, prect.y
DrawSync(0); // Wait for the drawing to end
if (tparam->mode & 0x8){ // check 4th bit // If 4th bit == 1, TIM has a CLUT
LoadImage(tparam->crect, tparam->caddr); // Load it to VRAM at position crect.x, crect.y
DrawSync(0); // Wait for drawing to end
}
}
void init(void)
{
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
SetGeomOffset(CENTERX,CENTERY);
SetGeomScreen(CENTERX);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 128, 128, 128);
setRGB0(&draw[1], 128, 128, 128);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main(void)
{
int i;
MATRIX IDMATRIX = identity(3); // Generate 3x3 identity matrix
POLY_GT4 *poly = {0}; // pointer to a POLY_G4
SVECTOR RotVector = {0, 0, 0}; // Initialize rotation vector {x, y, z}
VECTOR MovVector = {0, 0, 120, 0}; // Initialize translation vector {x, y, z}
SVECTOR VertPos[4] = { // Set initial vertices position relative to 0,0 - see here : https://psx.arthus.net/docs/poly_f4.jpg
{-32, -32, 0 }, // Vert 1
{-32, 32, 0 }, // Vert 2
{ 32, -32, 0 }, // Vert 3
{ 32, 32, 0 } // Vert 4
};
MATRIX PolyMatrix = IDMATRIX;
DR_TPAGE * bousai_tpage;
long polydepth;
long polyflag;
// Texture window
DR_MODE * dr_mode; // Pointer to dr_mode prim
RECT tws = {64, 32, 32, 32}; // Texture window coordinates : x, y, w, h
// See libref47.pdf, p.242, 7-6, table 7-2 for possible values
init();
LoadTexture(_binary____TIM_bousai_tim_start, &bousai);
while (1)
{
ClearOTagR(ot[db], OTLEN);
poly = (POLY_GT4 *)nextpri; // Set poly to point to the address of the next primitiv in the buffer
// Set transform matrices for this polygon
RotMatrix(&RotVector, &PolyMatrix); // Apply rotation matrix
TransMatrix(&PolyMatrix, &MovVector); // Apply translation matrix
SetRotMatrix(&PolyMatrix); // Set default rotation matrix
SetTransMatrix(&PolyMatrix); // Set default transformation matrix
setPolyGT4(poly); // Initialize poly as a POLY_F4
poly->tpage = getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y);
setRGB0(poly, 128, 128, 128); // Set vertice 1 color
setRGB1(poly, 255, 0, 0); // Set vertice 2 color
setRGB2(poly, 0, 255, 0); // Set vertice 3 color
setRGB3(poly, 0, 0, 255); // Set vertice 4 color
RotTransPers4(
&VertPos[0], &VertPos[1], &VertPos[2], &VertPos[3],
(long*)&poly->x0, (long*)&poly->x1, (long*)&poly->x2, (long*)&poly->x3,
&polydepth,
&polyflag
); // Perform coordinate and perspective transformation for 4 vertices
setUV4(poly, 0, 0, 0, 144, 144, 0, 144, 144); // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right
RotVector.vy += 14; // Apply rotation on Z-axis. On PSX, the Z-axis is pointing away from the screen.
addPrim(ot[db], poly); // add poly to the Ordering table
nextpri += sizeof(POLY_GT4); // increment nextpri address with size of a POLY_GT4 struct
// drawing mode primitive
dr_mode = (DR_MODE *)nextpri; // initialize drawing mode primitive
setDrawMode(dr_mode, 1, 0, getTPage(bousai.mode&0x3, 0, bousai.prect->x, bousai.prect->y), &tws); //set texture window
addPrim(ot[db], dr_mode);
nextpri += sizeof(DR_MODE); // increment nextpri address with size of a DR_MODE struct
FntPrint("Hello textured shaded !");
FntFlush(-1);
display();
}
return 0;
}

View File

@ -0,0 +1,6 @@
TARGET = hello_poly_inline
SRCS = hello_poly_inline.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

View File

@ -0,0 +1,214 @@
// Hello poly ! Inline / DMPSX version
//
// Ref : /psyq/DOCS/Devrefs/Inlinref.pdf, p.18
// https://psx-spx.consoledev.net/geometrytransformationenginegte/
// PSX / Z+
// screen /
//coordinate +-----X+
//system / |
// eye | Y+
//
// Credits, thanks : Nicolas Noble, Sickle, Lameguy64 @ psxdev discord : https://discord.com/invite/N2mmwp
// https://discord.com/channels/642647820683444236/663664210525290507/834831466100949002
#include <sys/types.h>
#include <stdio.h>
#include <libetc.h>
#include <libgte.h>
#include <libgpu.h>
// OldWorld PsyQ has a inline_c.h file for inline GTE functions. We have to use the one at https://github.com/grumpycoders/pcsx-redux/blob/07f9b02d1dbb68f57a9f5b9773041813c55a4913/src/mips/psyq/include/inline_n.h
// because the real GTE commands are needed in nugget : https://psx-spx.consoledev.net/geometrytransformationenginegte/#gte-coordinate-calculation-commands
#include <inline_n.h>
//~ #include <gtemac.h> // gtemac contains macro versions of the libgte functions, worth checking out to see the operations order.
#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 >> 1 ) // Center of screen on x
#define CENTERY ( SCREENYRES >> 1 ) // Center of screen on y
#define MARGINX 0 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 7 // Text Field Height
#define OTLEN 10 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
void init(void)
{
ResetGraph(0);
// Initialize and setup the GTE
InitGeom();
//~ SetGeomOffset(CENTERX,CENTERY);
gte_SetGeomOffset(CENTERX,CENTERY);
gte_SetGeomScreen(CENTERX);
// Set display environment
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
// Set draw environment
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
// If PAL, use 320x256, hence 256 - 240 = 16 / 2 = 8 px vertical offset
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
SetDispMask(1);
// Set background color
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
// Wait for drawing
DrawSync(0);
// Wait for vsync
VSync(0);
// Flip DISP and DRAW env
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
//~ SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
// Flip db index
db = !db;
// Get next primitive in buffer
nextpri = primbuff[db];
}
int main(void)
{
long p, flag, OTz;
SVECTOR rotVector, rotVector4 = {0}; // Initialize rotation vector {x, y, z}
VECTOR transVector = {0, 0, CENTERX, 0}; // Initialize translation vector {x, y, z}
SVECTOR vertPos[4] = {
{ 0, -32, 0, 0 }, // Vert 1
{ 32, 0, 0, 0 }, // Vert 2
{ -32, 0, 0, 0 },
{ 0, 32, 0, 0 }
}; // Vert 3
MATRIX workMatrix = {0};
POLY_F3 * poly = {0}; // pointer to a POLY_F4
POLY_F4 * poly4 = {0}; // pointer to a POLY_F4
init();
while (1)
{
// Set Ordering table
ClearOTagR(ot[db], OTLEN);
// Draw on the left part of the screen
transVector.vx = -CENTERX/2;
// Increment rotation angle on Y axis
rotVector.vy += 8;
rotVector.vx -= 4 ;
// Find rotation matrix from vector, store in
RotMatrix_gte(&rotVector, &workMatrix);
// Ditto for translation
TransMatrix(&workMatrix, &transVector);
// Set the matrices we just found
gte_SetRotMatrix(&workMatrix);
gte_SetTransMatrix(&workMatrix);
// Cast next primitive in buffer as a POLY_F4 (see display() )
poly = (POLY_F3 *)nextpri;
// Draw a Tri
// Initialize poly as a POLY_F3
setPolyF3(poly);
// Set poly color - Hot pink
setRGB0(poly, 255, 0, 255);
// Store vertex positions for current polygon in registers v0,v1,v2
// Can be replaced by one gte_ldv3 call :
// gte_ldv3(&vertPos[0], &vertPos[1], &vertPos[2]);
gte_ldv0(&vertPos[0]);
gte_ldv1(&vertPos[1]);
gte_ldv2(&vertPos[2]);
// RotTransPers3 : Perform coordinate and perspective transformation for three vertices.
// Use gte_rtps() for one vertex.
gte_rtpt();
// Get screen coordinates from cop2 registers XY0,XY1,XY2 and store them in primitive's x0, y0, x1, y1, x2, y2 members.
// Can be replace with one gte_stsxy3() call :
// gte_stsxy3(&poly->x0, &poly->x1, &poly->x2);
// Can also be replaced with a primitive type dependant version :
// gte_stsxy3_f3(poly);
gte_stsxy0(&poly->x0);
gte_stsxy1(&poly->x1);
gte_stsxy2(&poly->x2);
// Get depth interpolation coefficient p
gte_stdp(&p);
// Get the flag - see libover47.pdf, p.143 for details on ppossible values
gte_stflg(&flag);
// Get screen coordinate Z/4
gte_stszotz(&OTz);
// GTE macro version - needs 'gtemac.h' to be included - uncomment l.21
//~ gte_RotTransPers3( &VertPos[0], &VertPos[1], &VertPos[2],
//~ &poly->x0, &poly->x1, &poly->x2,
//~ &p, &flag, &OTz );
// add poly to the Ordering table
addPrim(ot[db], poly);
// increment nextpri address with size of a POLY_F3 struct
nextpri += sizeof(POLY_F3);
// Draw a Quad
//
// The GTE rtpt can only transform 3 vertices at a time, so we have to do all operations as 3 + 1.
// Move to right of screen
transVector.vx = CENTERX/2;
// Increment rot on X/Y axis
rotVector4.vy -= 8 ;
rotVector4.vx -= 4 ;
// Set matrices
RotMatrix_gte(&rotVector4, &workMatrix);
TransMatrix(&workMatrix, &transVector);
gte_SetRotMatrix(&workMatrix);
gte_SetTransMatrix(&workMatrix);
// Cast a POLY_F4 at the address we just incremented.
poly4 = (POLY_F4 *)nextpri;
// Initialize poly as a POLY_F4
setPolyF4(poly4);
// Set Poly color - Blue
setRGB0(poly4, 0, 255, 255);
// Transform 3 first vertices
gte_ldv3(&vertPos[0], &vertPos[1], &vertPos[2]);
gte_rtpt();
gte_stsxy3_f4(poly4);
// Transform remaining vertex
gte_ldv0(&vertPos[3]);
gte_rtps();
// SXY3 is set with gte_stsxy() or gte_stsxy2() ¯\_(ツ)_/¯
gte_stsxy(&poly4->x3);
// Get p, flag and OTz
gte_stdp(&p);
gte_stflg(&flag);
gte_stszotz(&OTz);
addPrim(ot[db], poly4); // add poly to the Ordering table
nextpri += sizeof(POLY_F4); // increment nextpri address with size of a POLY_F3 struct
// Display text
FntPrint("Hello Inline GTE !\n");
FntFlush(-1);
display();
}
return 0;
}

6
hello_sio/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_sio
SRCS = hello_sio.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

219
hello_sio/hello_sio.c Normal file
View File

@ -0,0 +1,219 @@
// hello_sio example
//
// This example will display the RX data in a 64 char rolling buffer.
//
// Use minicom or any other serial comm program and a serial/USB cable.
//
// Relevant doc is libref47.pdf, l.1120-1127
//
// Schnappy - 04/2021
//
// Based on : ../psyq/psx/sample/serial/SIO
//
// sio echo back
// 1.00 Jan.28.1997 shino
#include <sys/types.h>
#include <libgte.h>
#include <libgpu.h>
#include <libetc.h>
#include <stdio.h>
// Needed for SIO operations
#include <libsio.h>
// Needed for manipulating strings
#include <string.h>
// Display stuff (see hello_tile for the basics)
#define VMODE 0
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define OTLEN 2048 // Maximum number of OT entries
#define PRIMBUFFLEN 32768 // Maximum number of POLY_GT3 primitives
// Display and draw environments, double buffered
DISPENV disp[2];
DRAWENV draw[2];
u_long ot[2][OTLEN]; // Ordering table (contains addresses to primitives)
char primbuff[2][PRIMBUFFLEN] = {0}; // Primitive list // That's our prim buffer
char * nextpri = primbuff[0]; // Primitive counter
short db = 0; // Current buffer counter
// SIO
#define MAX_CHARS 64
u_char SIO = 1; // Is SIO enabled ?
u_char SIOinit = 0; // Is SIO initialized ?
// Prototypes
void init(void);
void display(void);
void init(){
// Reset the GPU before doing anything and the controller
ResetGraph(0);
// Set the display and draw environments
SetDefDispEnv(&disp[0], 0, 0 , SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
// If in PAL mode, add vertical offset
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 0, 0, 255);
setRGB0(&draw[1], 0, 0, 255);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Init font system
FntLoad(960, 0);
FntOpen(16, 16, 196, 64, 0, 256);
}
void display(void){
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
db = !db;
}
int main() {
init();
// Main loop
while (1) {
// Buffer for the RX data of size MAX_CHARS
static char buffer[ MAX_CHARS ] = {0};
// If SIO flag is set, initialize and get data
if( SIO ){
// Is SIO is not initialized, dot it
if( ! SIOinit ){
ResetCallback();
// Load SIO driver at 115200bps
AddSIO(115200);
ResetGraph(0);
// Use _sio_control to clear driver status error-related bits
// See psyq's libref47.pdf, p.1125 for the commands and status tables
_sio_control(2,1,0);
SIOinit = 1;
}
// Limit input buffer to MAX_CHARS chars, making it a rolling buffer
if( strlen(buffer) > MAX_CHARS ){
// If that limit is reached, remove first char in string
memmove(buffer, buffer + 1, strlen(buffer));
}
// Check if sio driver is able to write communications data
// If so, this means reading is not occuring
if( _sio_control(0,0,0) & SR_RXRDY ){ // SR_RXRDY == 0x2
// Read byte
char c = _sio_control(0,4,0);
// Add to buffer
strncat(buffer, &c, 1);
}
}
// END SIO FUN
FntPrint("Hello Serial!\n\n");
if( buffer ){
FntPrint("%s", buffer);
}
FntFlush(-1);
display();
}
return 0;
}

9
hello_sprt/Makefile Normal file
View File

@ -0,0 +1,9 @@
TARGET = hello_sprt
SRCS = hello_sprt.c \
../TIM/TIM16.tim \
../TIM/TIM8.tim \
../TIM/TIM4.tim \
include ../common.mk
include ../thirdparty/nugget/common.mk \

232
hello_sprt/hello_sprt.c Normal file
View File

@ -0,0 +1,232 @@
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define MARGINX 32 // margins for text display
#define MARGINY 44
#define FONTSIZE 8 * 3 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1}; // double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
// Embed TIM files
// See https://github.com/ABelliqueux/nolibgs_hello_worlds#embedding-binary-data-in-a-ps-exe
// 16bpp TIM
extern unsigned long _binary____TIM_TIM16_tim_start[];
extern unsigned long _binary____TIM_TIM16_tim_end[];
extern unsigned long _binary____TIM_TIM16_tim_length;
// 8bpp TIM
extern unsigned long _binary____TIM_TIM8_tim_start[];
extern unsigned long _binary____TIM_TIM8_tim_end[];
extern unsigned long _binary____TIM_TIM8_TIM_length;
// 4bpp TIM
extern unsigned long _binary____TIM_TIM4_tim_start[];
extern unsigned long _binary____TIM_TIM4_tim_end[];
extern unsigned long _binary____TIM_TIM4_tim_length;
TIM_IMAGE TIM_16;
TIM_IMAGE TIM_8;
TIM_IMAGE TIM_4;
void LoadTexture(u_long * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous
OpenTIM(tim); // Open the tim binary data, feed it the address of the data in memory
ReadTIM(tparam); // This read the header of the TIM data and sets the corresponding members of the TIM_IMAGE structure
LoadImage(tparam->prect, tparam->paddr); // Transfer the data from memory to VRAM at position prect.x, prect.y
DrawSync(0); // Wait for the drawing to end
if (tparam->mode & 0x8){ // check 4th bit // If 4th bit == 1, TIM has a CLUT
LoadImage(tparam->crect, tparam->caddr); // Load it to VRAM at position crect.x, crect.y
DrawSync(0); // Wait for drawing to end
}
}
void init(void)
{
ResetGraph(0);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
DrawOTag(ot[db] + OTLEN - 1);
db = !db;
nextpri = primbuff[db];
}
int main(void)
{
SPRT * sprt_16b; // Define 3 pointers to SPRT struct
SPRT * sprt_8b;
SPRT * sprt_4b;
DR_TPAGE * tpage_16b; // Define 3 pointers to DR_TPAGE struct. We need three because our images are on three
DR_TPAGE * tpage_8b; // different texture pages.
DR_TPAGE * tpage_4b;
init();
LoadTexture(_binary____TIM_TIM16_tim_start, &TIM_16); // Load everything to vram
LoadTexture(_binary____TIM_TIM8_tim_start, &TIM_8);
LoadTexture(_binary____TIM_TIM4_tim_start, &TIM_4);
while (1)
{
ClearOTagR(ot[db], OTLEN);
// Loading a 16 bit TIM
sprt_16b = (SPRT *)nextpri; // Cast whats at nexpri as a SPRT named sprt_16b
setSprt(sprt_16b); // Initialize the SPRT struct
setRGB0(sprt_16b, 128, 128, 128); // Set RGB color. 128,128,128 is neutral. You can color the image by adjusting these values
setXY0(sprt_16b, 28, MARGINY); // Set sprite position
setWH(sprt_16b, 64, 128 ); // Set sprite width and height
addPrim(ot[db], sprt_16b); // add the sprite primitive to the ordering table
nextpri += sizeof(SPRT); // increment nextpri so that it points just after sprt_16b in the primitive buffer
// Set Texture page for the 16bit tim : 768, 0 - No CLUT
// Note : You need to use setDrawTPage each time you want to use a texture that's on a different texture page
tpage_16b = (DR_TPAGE*)nextpri;
setDrawTPage(tpage_16b, 0, 1, // Set the Texture Page the texture we want resides on.
getTPage(TIM_16.mode&0x3, 0, // Here we are using bitmasking to deduce the picture mode : &0x3
TIM_16.prect->x, TIM_16.prect->y)); // In binary, 3 is 11, so we only keep the first two bits
// Values can be 00 (0), 01 (1), 10(2), respectively, 4bpp, 8bpp, 15bpp, 24bpp. See Fileformat47.pdf, p.180
// Similarly, we could use bitmasking to deduce if there is a CLUT by bitmasking the 4th bit : if(TIM_IMAGE.mode & 0x8) LoadImage... :
addPrim(ot[db], tpage_16b); // add the sprite primitive to the ordering table
nextpri += sizeof(DR_TPAGE); // Advance next primitive address
// Loading a 8 bit TIM
sprt_8b = (SPRT *)nextpri;
setSprt(sprt_8b);
setRGB0(sprt_8b, 128, 128, 128);
setXY0(sprt_8b, sprt_16b->x0 + sprt_16b->w + 32, MARGINY);
setWH(sprt_8b, 64, 128 );
setClut(sprt_8b, TIM_8.crect->x, TIM_8.crect->y); // Only difference here is we set the CLUT to the position of the VRAM we loaded the palette earlier (see LoadTexture())
addPrim(ot[db], sprt_8b);
nextpri += sizeof(SPRT);
// Set Texture page for the 8bit tim : 512, 256 - CLUT is at 0, 480
tpage_8b = (DR_TPAGE*)nextpri;
setDrawTPage(tpage_8b, 0, 1,
getTPage(TIM_8.mode&0x3, 0,
TIM_8.prect->x, TIM_8.prect->y));
addPrim(ot[db], tpage_8b);
nextpri += sizeof(DR_TPAGE);
// Loading a 4 bit TIM
sprt_4b = (SPRT *)nextpri;
setSprt(sprt_4b);
setRGB0(sprt_4b, 128, 128, 128);
setXY0(sprt_4b, sprt_8b->x0 + sprt_8b->w + 32, MARGINY);
setWH(sprt_4b, 64, 128 );
setClut(sprt_4b, TIM_4.crect->x, TIM_4.crect->y);
addPrim(ot[db], sprt_4b);
nextpri += sizeof(SPRT);
// Set Texture page for the 4bit tim : 512, 256 - CLUT is at 0, 480
tpage_4b = (DR_TPAGE*)nextpri;
setDrawTPage(tpage_4b, 0, 1,
getTPage(TIM_4.mode&0x3, 0,
TIM_4.prect->x, TIM_4.prect->y));
addPrim(ot[db], tpage_4b);
nextpri += sizeof(DR_TPAGE);
FntPrint("16 Bit! ");
FntPrint("8 Bit! ");
FntPrint("4 Bit!\n\n");
FntPrint("Check VRAM in emu to see the dif");
FntFlush(-1);
display();
}
return 0;
}

6
hello_tile/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_tile
SRCS = hello_tile.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

150
hello_tile/hello_tile.c Normal file
View File

@ -0,0 +1,150 @@
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define MARGINX 0 // margins for text display
#define MARGINY 32
#define FONTSIZE 8 * 7 // Text Field Height
#define OTLEN 8 // Ordering Table Length
DISPENV disp[2]; // Double buffered DISPENV and DRAWENV
DRAWENV draw[2];
u_long ot[2][OTLEN]; // double ordering table of length 8 * 32 = 256 bits / 32 bytes
char primbuff[2][32768] = {1};// double primitive buffer of length 32768 * 8 = 262.144 bits / 32,768 Kbytes
char *nextpri = primbuff[0]; // pointer to the next primitive in primbuff. Initially, points to the first bit of primbuff[0]
short db = 0; // index of which buffer is used, values 0, 1
void init(void)
{
ResetGraph(0);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(MARGINX, SCREENYRES - MARGINY - FONTSIZE, SCREENXRES - MARGINX * 2, FONTSIZE, 0, 280 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
// We're using a reverse OT, so we want to display the last item first. See PsyQ's LibRef47.pdf, p.277
DrawOTag(ot[db] + OTLEN - 1);
// Uncomment the following line to use a regular oredered OT. Uncomment l.100 accordingly
//~ DrawOTag(ot[db]);
db = !db;
nextpri = primbuff[db];
}
int main(void)
{
// These two tiles are added at the same OT index
TILE * blue_tile;
TILE * pink_tile;
// This one is added at a different OT index
TILE * yellow_tile;
init();
while (1)
{
// Initialize the reversed ordering table. This means the elements at index OTLEN - 1 is drawn first.
ClearOTagR(ot[db], OTLEN);
// Use regular order OT, uncomment l.77 accordingly
//~ ClearOTag(ot[db], OTLEN);
// yellow_tile is before pink and blue tile in the code,
// and it displays behind because it is added to a different ot index (od[db] + OTLEN - 1)
// Using a Regular or Reverse OT will have an effect on drawing order. (See lines 77 and 100)
yellow_tile = (TILE * ) nextpri; // yellow_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a TILE struc.
setTile(yellow_tile); // initialize the TILE structure ( fill the length and tag(?) value )
setXY0(yellow_tile, CENTERX - 32 , CENTERY - 48); // Set X,Y
setWH(yellow_tile, 128, 40); // Set Width, Height
setRGB0(yellow_tile, 255, 255, 0); // Set color
addPrim(ot[db] + OTLEN - 1, yellow_tile); // Add primitive to ordering table
nextpri += sizeof(TILE);
// blue_tile added at od[db] + OTLEN - 2
blue_tile = (TILE * ) nextpri; // blue_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a blue_tile struc.
setTile(blue_tile); // initialize the blue_tile structure ( fill the length and tag(?) value )
setXY0(blue_tile, CENTERX - 16, CENTERY - 32); // Set X,Y
setWH(blue_tile, 32, 64); // Set Width, Height
setRGB0(blue_tile, 60, 180, 255); // Set color
addPrim(ot[db] + OTLEN - 2, blue_tile); // Add primitive to ordering table
nextpri += sizeof(TILE); // Increment the adress nextpri points to by the size of TILE struct
// pink_tile is after blue_tile in the code,
// so it is drawn before, thus under blue_tile.
// However, it is added at the same ot index (od[db] + OTLEN - 2)
// so using a Regular or Reverse OT won't have an effect on drawing order.
pink_tile = (TILE * ) nextpri; // pink_tile is a pointer to primbuf content at adress nextpri, that's cast (type converted) to a TILE struc.
setTile(pink_tile); // initialize the TILE structure ( fill the length and tag(?) value )
setXY0(pink_tile, CENTERX, CENTERY - 64); // Set X,Y
setWH(pink_tile, 64, 64); // Set Width, Height
setRGB0(pink_tile, 255, 32, 255); // Set color
addPrim(ot[db] + OTLEN - 2, pink_tile); // Add primitive to ordering table
nextpri += sizeof(TILE);
FntPrint("Hello tile !");
FntFlush(-1);
display();
}
return 0;
}

7
hello_vag/Makefile Normal file
View File

@ -0,0 +1,7 @@
TARGET = hello_vag
SRCS = hello_vag.c \
../VAG/hello_poly.vag
include ../common.mk
include ../thirdparty/nugget/common.mk \

275
hello_vag/hello_vag.c Normal file
View File

@ -0,0 +1,275 @@
// VAGDEMO2020 by Schnappy
// December 2020
// Based on VAGDEMO_FIXED by Yagotzirck
// Based on VAGDEMO by Shadow
// based on psyq/addons/sound/TUTO3.C
//
//
// Load a VAG file to SPU sound buffer and play it back.
//
// WAV creation: use ffmpeg to create a 16-bit ADPCM mono WAV file - change -ar to reduce filesize (and quality)
// $ ffmpeg -i input.mp3 -acodec pcm_s16le -ac 1 -ar 44100 output.wav
//
// WAV to VAG convertion using WAV2VAG : https://github.com/ColdSauce/psxsdk/blob/master/tools/wav2vag.c
// change -freq according to the -ar setting above
// $ wav2vag input.wav output.vag -sraw16 -freq=44100 (-L)
//
// Alternatively, you can use PsyQ VAGEDIT.EXE to change the sampling frequency of an existing VAG file.
//
// Docs : see libformat47.pdf p.209
// libover47.pdf, p.271
// libref47.pdf, p.980
// URLS : http://psx.arthus.net/code/VAG/
#include <sys/types.h>
#include <stdio.h>
#include <libgte.h>
#include <libetc.h>
#include <libgpu.h>
// Sound system
#include <libsnd.h>
#include <libspu.h>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320
#define SCREENYRES 240
#define CENTERX SCREENXRES/2
#define CENTERY SCREENYRES/2
#define MARGINX 0 // margins for text display
#define MARGINY 32
#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
// Sound stuff
#define MALLOC_MAX 3 // Max number of time we can call SpuMalloc
//~ // convert Little endian to Big endian
#define SWAP_ENDIAN32(x) (((x)>>24) | (((x)>>8) & 0xFF00) | (((x)<<8) & 0x00FF0000) | ((x)<<24))
typedef struct VAGheader{ // All the values in this header must be big endian
char id[4]; // VAGp 4 bytes -> 1 char * 4
unsigned int version; // 4 bytes
unsigned int reserved; // 4 bytes
unsigned int dataSize; // (in bytes) 4 bytes
unsigned int samplingFrequency;// 4 bytes
char reserved2[12]; // 12 bytes -> 1 char * 12
char name[16]; // 16 bytes -> 1 char * 16
// Waveform data after that
}VAGhdr;
SpuCommonAttr commonAttributes; // structure for changing common voice attributes
SpuVoiceAttr voiceAttributes ; // structure for changing individual voice attributes
u_long vag_spu_address; // address allocated in memory for first sound file
// DEBUG : these allow printing values for debugging
u_long spu_start_address;
u_long get_start_addr;
u_long transSize;
// Memory management table ; allow MALLOC_MAX calls to SpuMalloc() - ibref47.pdf p.1044
char spu_malloc_rec[SPU_MALLOC_RECSIZ * (2 + MALLOC_MAX+1)];
// VAG files
// We're using GrumpyCoder's Nugget wrapper to compile the code with a modern GCC : https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/psyq
// To include binary files in the exe, add your VAG files to the SRCS variable in Makefile
// and in common.mk, add this rule to include *.vag files :
//
//~ %.o: %.vag
//~ $(PREFIX)-objcopy -I binary --set-section-alignment .data=4 --rename-section .data=.rodata,alloc,load,readonly,data,contents -O elf32-tradlittlemips -B mips $< $@
// hello_poly.vag - 44100 Khz
extern unsigned char _binary____VAG_hello_poly_vag_start[]; // filename must begin with _binary_ followed by the full path, with . and / replaced, and then suffixed with _ and end with _start[]; or end[];
extern unsigned char _binary____VAG_hello_poly_vag_end[]; // Going up one directory level is 4 '_' : ____ as ./ is replaced by __
// https://discord.com/channels/642647820683444236/663664210525290507/780866265077383189
void initGraph(void)
{
ResetGraph(0);
SetDefDispEnv(&disp[0], 0, 0, SCREENXRES, SCREENYRES);
SetDefDispEnv(&disp[1], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[0], 0, SCREENYRES, SCREENXRES, SCREENYRES);
SetDefDrawEnv(&draw[1], 0, 0, SCREENXRES, SCREENYRES);
if (VMODE)
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8;
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50);
setRGB0(&draw[1], 50, 50, 50);
draw[0].isbg = 1;
draw[1].isbg = 1;
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
FntLoad(960, 0);
FntOpen(8, 60, 304, 200, 0, 500 );
}
void display(void)
{
DrawSync(0);
VSync(0);
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
SetDispMask(1);
db = !db;
}
// Audio initialisation & functions
void initSnd(void){
SpuInitMalloc(MALLOC_MAX, spu_malloc_rec); // Maximum number of blocks, mem. management table address.
commonAttributes.mask = (SPU_COMMON_MVOLL | SPU_COMMON_MVOLR); // Mask which attributes to set
commonAttributes.mvol.left = 0x3fff; // Master volume left
commonAttributes.mvol.right = 0x3fff; // see libref47.pdf, p.1058
SpuSetCommonAttr(&commonAttributes); // set attributes
SpuSetIRQ(SPU_OFF);
}
u_long sendVAGtoRAM(unsigned int VAG_data_size, unsigned char *VAG_data){
u_long size;
SpuSetTransferMode(SpuTransByDMA); // DMA transfer; can do other processing during transfer
size = SpuWrite (VAG_data + sizeof(VAGhdr), VAG_data_size); // transfer VAG_data_size bytes from VAG_data address to sound buffer
SpuIsTransferCompleted (SPU_TRANSFER_WAIT); // Checks whether transfer is completed and waits for completion
return size;
}
void setVoiceAttr(unsigned int pitch, long channel, unsigned long soundAddr ){
voiceAttributes.mask= //~ Attributes (bit string, 1 bit per attribute)
(
SPU_VOICE_VOLL |
SPU_VOICE_VOLR |
SPU_VOICE_PITCH |
SPU_VOICE_WDSA |
SPU_VOICE_ADSR_AMODE |
SPU_VOICE_ADSR_SMODE |
SPU_VOICE_ADSR_RMODE |
SPU_VOICE_ADSR_AR |
SPU_VOICE_ADSR_DR |
SPU_VOICE_ADSR_SR |
SPU_VOICE_ADSR_RR |
SPU_VOICE_ADSR_SL
);
voiceAttributes.voice = channel; //~ Voice (low 24 bits are a bit string, 1 bit per voice )
voiceAttributes.volume.left = 0x1000; //~ Volume
voiceAttributes.volume.right = 0x1000; //~ Volume
voiceAttributes.pitch = pitch; //~ Interval (set pitch)
voiceAttributes.addr = soundAddr; //~ Waveform data start address
voiceAttributes.a_mode = SPU_VOICE_LINEARIncN; //~ Attack rate mode = Linear Increase - see libref47.pdf p.1091
voiceAttributes.s_mode = SPU_VOICE_LINEARIncN; //~ Sustain rate mode = Linear Increase
voiceAttributes.r_mode = SPU_VOICE_LINEARDecN; //~ Release rate mode = Linear Decrease
voiceAttributes.ar = 0x0; //~ Attack rate
voiceAttributes.dr = 0x0; //~ Decay rate
voiceAttributes.rr = 0x0; //~ Release rate
voiceAttributes.sr = 0x0; //~ Sustain rate
voiceAttributes.sl = 0xf; //~ Sustain level
SpuSetVoiceAttr(&voiceAttributes); // set attributes
}
void playSFX(void){
SpuSetKey(SpuOn,SPU_0CH); // Set several channels by ORing each channel bit ; ex : SpuSetKey(SpuOn,SPU_0CH | SPU_3CH | SPU_8CH); channels 0, 3, 8 are on.
}
int main(void)
{
short counter = 0;
const VAGhdr * VAGfileHeader = (VAGhdr *) _binary____VAG_hello_poly_vag_start; // get header of VAG file
// From libover47.pdf :
// The sampling frequency of the original audio file can be used to determine the pitch
// at which to play the VAG. pitch = (sampling frequency << 12)/44100L
// Ex: 44.1kHz=0x1000 22.05kHz=0x800 etc
unsigned int pitch = (SWAP_ENDIAN32(VAGfileHeader->samplingFrequency) << 12) / 44100L;
SpuInit(); // Initialize SPU. Called only once.
initSnd();
//~ // First VAG
vag_spu_address = SpuMalloc(SWAP_ENDIAN32(VAGfileHeader->dataSize)); // Allocate an area of dataSize bytes in the sound buffer.
spu_start_address = SpuSetTransferStartAddr(vag_spu_address); // Sets a starting address in the sound buffer
get_start_addr = SpuGetTransferStartAddr(); // SpuGetTransferStartAddr() returns current sound buffer transfer start address.
transSize = sendVAGtoRAM(SWAP_ENDIAN32(VAGfileHeader->dataSize), _binary____VAG_hello_poly_vag_start);
// set VAG to channel
setVoiceAttr(pitch, SPU_0CH, vag_spu_address);
initGraph();
while (1)
{
if(!counter){
playSFX();
counter = 180;
}
FntPrint("\nPitch : %08x-%dKhz", pitch, (SWAP_ENDIAN32(VAGfileHeader->samplingFrequency)) );
FntPrint("\nSet Start addr : %08x", vag_spu_address);
FntPrint("\nReturn start addr : %08x", spu_start_address);
FntPrint("\nGet Start addr : %08x", get_start_addr);
FntPrint("\nSend size : %08x", SWAP_ENDIAN32(VAGfileHeader->dataSize));
FntPrint("\nReturn size : %08x\n", transSize);
FntPrint("\nCounter : %d\n", counter);
FntFlush(-1);
counter --;
display();
}
return 0;
}

6
hello_world/Makefile Normal file
View File

@ -0,0 +1,6 @@
TARGET = hello_world
SRCS = hello_world.c \
include ../common.mk
include ../thirdparty/nugget/common.mk \

86
hello_world/hello_world.c Normal file
View File

@ -0,0 +1,86 @@
// This is stolen from Lameguy64 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>
#define VMODE 0 // Video Mode : 0 : NTSC, 1: PAL
#define SCREENXRES 320 // Screen width
#define SCREENYRES 240 // Screen height
#define CENTERX SCREENXRES/2 // Center of screen on x
#define CENTERY SCREENYRES/2 // Center of screen on y
#define MARGINX 0 // margins for text display
#define MARGINY 32
#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
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]
if (VMODE) // PAL
{
SetVideoMode(MODE_PAL);
disp[0].screen.y += 8; // add offset : 240 + 8 + 8 = 256
disp[1].screen.y += 8;
}
setRGB0(&draw[0], 50, 50, 50); // set color for first draw area
setRGB0(&draw[1], 50, 50, 50); // set color for second draw area
draw[0].isbg = 1; // set mask for draw areas. 1 means repainting the area with the RGB color each frame
draw[1].isbg = 1;
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, SCREENYRES - MARGINY - FONTSIZE, 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]);
SetDispMask(1); // Display on screen
db = !db; // flip db value (0 or 1)
}
int main(void)
{
init(); // execute init()
while (1) // infinite loop
{
FntPrint("Hello world !"); // Send string to print stream
FntFlush(-1); // Draw printe stream
display(); // Execute display()
}
return 0;
}

67
includes/CPUMAC.H Normal file
View File

@ -0,0 +1,67 @@
/*
** cpumac.h
mike acton
*/
// cpu_ldr(cpu register,data pointer)
// copy 32bit data from dp to r
#define cpu_ldr(r,dp)\
asm(\
"lw %0, 0(%1);"\
: "=r" (r)\
: "r" (dp)\
)
// cpu_gted0(cpu register)
// copy 32bit data from r to gte register 0
#define cpu_gted0(r)\
asm(\
"mtc2 %0, $0;"\
:\
: "r" (r)\
)
// cpu_gted1(cpu register)
// copy 32bit data from r to gte register 1
#define cpu_gted1(r)\
asm(\
"mtc2 %0, $1;"\
:\
: "r" (r)\
)
// cpu_gted2(cpu register)
// copy 32bit data from r to gte register 2
#define cpu_gted2(r)\
asm(\
"mtc2 %0, $2;"\
:\
: "r" (r)\
)
// cpu_gted3(cpu register)
// copy 32bit data from r to gte register 3
#define cpu_gted3(r)\
asm(\
"mtc2 %0, $3;"\
:\
: "r" (r)\
)
// cpu_gted4(cpu register)
// copy 32bit data from r to gte register 4
#define cpu_gted4(r)\
asm(\
"mtc2 %0, $4;"\
:\
: "r" (r)\
)
// cpu_gted5(cpu register)
// copy 32bit data from r to gte register 5
#define cpu_gted5(r)\
asm(\
"mtc2 %0, $5;"\
:\
: "r" (r)\
)

1
thirdparty/nugget vendored Submodule

@ -0,0 +1 @@
Subproject commit 6483f1e13b5c89932500129548e8aa8f2a026f25