Browse Source

First import, with bits of code taken from the MDL viewer prototype, split up into organized units.

tess_experiment
Nico de Poel 3 years ago
commit
ea44f4e99c
  1. 2
      .gitignore
  2. 25
      CMakeLists.txt
  3. 23
      CMakePresets.json
  4. 29
      asset.c
  5. 13
      asset.h
  6. BIN
      atlas-e1m1.tim
  7. BIN
      atlas-e2m2.tim
  8. 16
      common.h
  9. 131
      display.c
  10. 13
      display.h
  11. 124
      input.c
  12. 7
      input.h
  13. 34
      iso.xml
  14. 54
      main.c
  15. 4
      system.cnf
  16. 19
      time.c
  17. 9
      time.h

2
.gitignore

@ -0,0 +1,2 @@
.vscode/
build/

25
CMakeLists.txt

@ -0,0 +1,25 @@
# PSn00bSDK example CMake script
# (C) 2021 spicyjpeg - MPL licensed
cmake_minimum_required(VERSION 3.20)
project(
PSn00bSDK-ps1bsp
LANGUAGES C CXX ASM
VERSION 1.0.0
DESCRIPTION "PS1 BSP Viewer"
HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
)
file(GLOB _sources *.c)
psn00bsdk_add_executable(ps1bsp STATIC ${_sources})
psn00bsdk_target_incbin(ps1bsp PRIVATE tim_e1m1 atlas-e1m1.tim)
psn00bsdk_target_incbin(ps1bsp PRIVATE tim_e2m2 atlas-e2m2.tim)
psn00bsdk_add_cd_image(
iso # Target name
ps1bsp # Output file name (= ps1bsp.bin + ps1bsp.cue)
iso.xml # Path to config file
DEPENDS ps1bsp
)

23
CMakePresets.json

@ -0,0 +1,23 @@
{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 20,
"patch": 0
},
"configurePresets": [
{
"name": "default",
"displayName": "Default configuration",
"description": "Use this preset to build the project using PSn00bSDK.",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake",
"PSN00BSDK_TC": "",
"PSN00BSDK_TARGET": "mipsel-none-elf"
}
}
]
}

29
asset.c

@ -0,0 +1,29 @@
#include "common.h"
#include "asset.h"
void asset_loadTexture(const u_long* tim, ps1texture_t *texture)
{
TIM_IMAGE* tparam;
GetTimInfo(tim, tparam);
// This freezes up if the TIM image has weird dimensions
LoadImage(tparam->prect, tparam->paddr);
// Upload CLUT for palettized images
if (tparam->mode & 0x8)
{
LoadImage(tparam->crect, tparam->caddr);
}
DrawSync(0);
if (texture != NULL)
{
texture->prect = *tparam->prect;
texture->crect = *tparam->crect;
texture->mode = tparam->mode;
texture->uoffs = (texture->prect.x % 64) << (2 - (texture->mode & 0x3));
texture->voffs = (texture->prect.y & 0xFF);
}
}

13
asset.h

@ -0,0 +1,13 @@
#ifndef __ASSET_H__
#define __ASSET_H__
typedef struct
{
RECT prect, crect;
int mode;
int uoffs, voffs;
} ps1texture_t;
void asset_loadTexture(const u_long* tim, ps1texture_t *texture);
#endif // __ASSET_H__

BIN
atlas-e1m1.tim

BIN
atlas-e2m2.tim

16
common.h

@ -0,0 +1,16 @@
#ifndef __COMMON_H__
#define __COMMON_H__
#include <stdio.h>
#include <sys/types.h>
#include <psxapi.h>
#include <psxetc.h>
#include <psxgte.h>
#include <psxgpu.h>
#define RotMatrixQ RotMatrix // TODO: temporary hack to allow Quake-specific code without implementation
extern VECTOR cam_pos;
extern SVECTOR cam_rot;
#endif // __COMMON_H__

131
display.c

@ -0,0 +1,131 @@
#include "common.h"
#include "display.h"
#include <inline_c.h>
// Define display/draw environments for double buffering
static DISPENV disp[2];
static DRAWENV draw[2];
static int db;
u_long ot[2][OTLEN]; // Ordering tables, two arrays for double buffering. These are basically the buckets for bucket sorting of polygons.
// You can also see them as "layers" in the modern 3D graphics sense, but they serve a more immediate role for polygon ordering.
// Layer 0 is free for overlays, as polygons at depth 0 will be clipped.
char primbuff[2][65536]; // Primitive buffer, just a raw buffer of bytes to use as a pool for primitives
char *nextpri;
const MATRIX identity = {
ONE, 0, 0,
0, ONE, 0,
0, 0, ONE,
0, 0, 0,
};
// Transform to change the coordinate system from PS1 Default (Y down, Z forward) to Quake (Z up, Y forward)
const MATRIX quake_swizzle = {
ONE, 0, 0,
0, 0, -ONE,
0, ONE, 0,
0, 0, 0,
};
MATRIX light_cols = {
ONE, 0, 0,
ONE, 0, 0,
ONE, 0, 0
};
MATRIX light_dirs = {
ONE, 0, 0,
0, 0, 0,
0, 0, 0
};
// Scale X coordinates to correct the aspect ratio for the chosen resolution
VECTOR aspect_scale = { SCREENWIDTH * ONE / 320 , ONE, ONE };
void display_init()
{
// This not only resets the GPU but it also installs the library's
// ISR subsystem to the kernel
ResetGraph(0);
SetVideoMode(MODE_NTSC);
// Define display environments, first on top and second on bottom
SetDefDispEnv(&disp[0], 0, 0, SCREENWIDTH, SCREENHEIGHT);
SetDefDispEnv(&disp[1], 0, SCREENHEIGHT, SCREENWIDTH, SCREENHEIGHT);
// Define drawing environments, first on bottom and second on top
SetDefDrawEnv(&draw[0], 0, SCREENHEIGHT, SCREENWIDTH, SCREENHEIGHT);
SetDefDrawEnv(&draw[1], 0, 0, SCREENWIDTH, SCREENHEIGHT);
// Set and enable clear color
setRGB0(&draw[0], 49, 77, 121);
setRGB0(&draw[1], 49, 77, 121);
draw[0].isbg = 1;
draw[0].dtd = 1;
draw[1].isbg = 1;
draw[1].dtd = 1;
// Clear double buffer counter
db = 0;
// Apply the GPU environments
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Load test font
FntLoad(960, 448);
// Open up a test font text stream
FntOpen(0, 8, SCREENWIDTH, SCREENHEIGHT, 0, 200);
// TODO: OT initialization
// Initialize GTE
InitGeom();
gte_SetGeomOffset(SCREENWIDTH >> 1, SCREENHEIGHT >> 1);
gte_SetGeomScreen(180); // Screen depth for FOV control. Determines the distance of the camera to the near plane.
}
void display_start()
{
ClearOTagR(ot[db], OTLEN);
gte_SetBackColor(48, 48, 48); // Ambient light color
gte_SetColorMatrix(&light_cols); // Light color (up to three different lights)
MATRIX proj_matrix = quake_swizzle; // Swizzle coordinates so that everything is in Quake coordinate system (Z up)
ScaleMatrixL(&proj_matrix, &aspect_scale); // Apply aspect ratio correction for the current resolution
MATRIX view_matrix;
SVECTOR trot = { -cam_rot.vx, -cam_rot.vy, -cam_rot.vz, 0 }; // Inverse camera rotation (in Quake coordinates)
VECTOR tpos = { -cam_pos.vx, -cam_pos.vy, -cam_pos.vz }; // Inverse camera position (in Quake coordinates)
RotMatrixQ(&trot, &view_matrix); // Set camera rotation part of the view matrix
ApplyMatrixLV(&view_matrix, &tpos, &tpos); // Apply camera rotation to camera position
TransMatrix(&view_matrix, &tpos); // Apply transformed position to the translation part of the view matrix
// Compose view and projection matrices to obtain a combined view-projection matrix
CompMatrixLV(&proj_matrix, &view_matrix, &view_matrix);
}
void display_finish()
{
// Flip buffer index
db = !db;
// Wait for all drawing to complete
DrawSync(0);
// Wait for vertical sync to cap the logic to 60fps (or 50 in PAL mode)
// and prevent screen tearing
VSync(0);
// Switch pages
PutDispEnv(&disp[db]);
PutDrawEnv(&draw[db]);
// Enable display output, ResetGraph() disables it by default
SetDispMask(1);
}

13
display.h

@ -0,0 +1,13 @@
#ifndef __DISPLAY_H__
#define __DISPLAY_H__
#define SCREENWIDTH 512
#define SCREENHEIGHT 240
#define OTLEN 1024
void display_init();
void display_start();
void display_finish();
#endif // __DISPLAY_H__

124
input.c

@ -0,0 +1,124 @@
#include "common.h"
#include "input.h"
#include <psxpad.h>
static u_char padBuffer[2][34];
static const int moveSpeed = 32;
static const short rotSpeed = 32;
static const char deadZone = 0x30;
void input_init()
{
InitPAD(padBuffer[0], 34, padBuffer[1], 34);
padBuffer[0][0] = padBuffer[0][1] = 0xFF;
padBuffer[1][0] = padBuffer[1][1] = 0xFF;
StartPAD();
ChangeClearPAD(1); // Avoid issues with VSync timeouts caused by StartPAD
}
void input_process()
{
// Check if we have a connected controller on port 1
if (padBuffer[0][0] != 0)
return;
// Determine direction vectors of the camera
MATRIX cam_mtx;
RotMatrixQ(&cam_rot, &cam_mtx);
u_short buttons = *((u_short*)(padBuffer[0]+2));
if (!(buttons & PAD_UP))
{
// Move forward (+Y)
cam_pos.vx += (cam_mtx.m[0][1] * moveSpeed) >> 12;
cam_pos.vy += (cam_mtx.m[1][1] * moveSpeed) >> 12;
cam_pos.vz += (cam_mtx.m[2][1] * moveSpeed) >> 12;
}
if (!(buttons & PAD_DOWN))
{
// Move backward (-Y)
cam_pos.vx -= (cam_mtx.m[0][1] * moveSpeed) >> 12;
cam_pos.vy -= (cam_mtx.m[1][1] * moveSpeed) >> 12;
cam_pos.vz -= (cam_mtx.m[2][1] * moveSpeed) >> 12;
}
if (!(buttons & PAD_LEFT))
{
// Rotate left
cam_rot.vz += rotSpeed;
}
if (!(buttons & PAD_RIGHT))
{
// Rotate right
cam_rot.vz -= rotSpeed;
}
if (!(buttons & PAD_TRIANGLE))
{
// Move up (+Z)
cam_pos.vx += (cam_mtx.m[0][2] * moveSpeed) >> 12;
cam_pos.vy += (cam_mtx.m[1][2] * moveSpeed) >> 12;
cam_pos.vz += (cam_mtx.m[2][2] * moveSpeed) >> 12;
}
if (!(buttons & PAD_CROSS))
{
// Move down (-Z)
cam_pos.vx -= (cam_mtx.m[0][2] * moveSpeed) >> 12;
cam_pos.vy -= (cam_mtx.m[1][2] * moveSpeed) >> 12;
cam_pos.vz -= (cam_mtx.m[2][2] * moveSpeed) >> 12;
}
if (!(buttons & PAD_L1))
{
// Strafe left (-X)
cam_pos.vx -= (cam_mtx.m[0][0] * moveSpeed) >> 12;
cam_pos.vy -= (cam_mtx.m[1][0] * moveSpeed) >> 12;
cam_pos.vz -= (cam_mtx.m[2][0] * moveSpeed) >> 12;
}
if (!(buttons & PAD_R1))
{
// Strafe right (+X)
cam_pos.vx += (cam_mtx.m[0][0] * moveSpeed) >> 12;
cam_pos.vy += (cam_mtx.m[1][0] * moveSpeed) >> 12;
cam_pos.vz += (cam_mtx.m[2][0] * moveSpeed) >> 12;
}
if (!(buttons & PAD_L2))
{
// Look down
cam_rot.vx -= rotSpeed;
}
if (!(buttons & PAD_R2))
{
// Look up
cam_rot.vx += rotSpeed;
}
// Check for analog controller
u_char padType = padBuffer[0][1] >> 4;
if (padType == 0x5 || padType == 0x7)
{
short rightJoyX = (short)(padBuffer[0][4]) - 0x80;
if (rightJoyX > -deadZone && rightJoyX < deadZone) rightJoyX = 0;
short rightJoyY = (short)(padBuffer[0][5]) - 0x80;
if (rightJoyY > -deadZone && rightJoyY < deadZone) rightJoyY = 0;
short leftJoyX = (short)(padBuffer[0][6]) - 0x80;
if (leftJoyX > -deadZone && leftJoyX < deadZone) leftJoyX = 0;
short leftJoyY = (short)(padBuffer[0][7]) - 0x80;
if (leftJoyY > -deadZone && leftJoyY < deadZone) leftJoyY = 0;
// Move forward/backward
cam_pos.vx -= (cam_mtx.m[0][1] * leftJoyY * moveSpeed) >> 19;
cam_pos.vy -= (cam_mtx.m[1][1] * leftJoyY * moveSpeed) >> 19;
cam_pos.vz -= (cam_mtx.m[2][1] * leftJoyY * moveSpeed) >> 19;
// Strafe left/right
cam_pos.vx += (cam_mtx.m[0][0] * leftJoyX * moveSpeed) >> 19;
cam_pos.vy += (cam_mtx.m[1][0] * leftJoyX * moveSpeed) >> 19;
cam_pos.vz += (cam_mtx.m[2][0] * leftJoyX * moveSpeed) >> 19;
// Rotate left/right
cam_rot.vz -= (rightJoyX * rotSpeed) >> 7;
// Look up/down
cam_rot.vx -= (rightJoyY * rotSpeed) >> 7;
}
}

7
input.h

@ -0,0 +1,7 @@
#ifndef __INPUT_H__
#define __INPUT_H__
void input_init();
void input_process();
#endif // __INPUT_H__

34
iso.xml

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is processed by CMake and used by mkpsxiso to build the CD image.
NOTE: all paths are relative to the build directory; if you want to include
a file from the source tree, you'll have to prepend its path with
${PROJECT_SOURCE_DIR}.
-->
<iso_project
image_name="${CD_IMAGE_NAME}.bin"
cue_sheet="${CD_IMAGE_NAME}.cue"
>
<track type="data">
<identifiers
system ="PLAYSTATION"
volume ="PSN00BSDK_PS1BSP"
volume_set ="PSN00BSDK_PS1BSP"
publisher ="MEIDOTEK"
data_preparer ="PSN00BSDK ${PSN00BSDK_VERSION}"
application ="PLAYSTATION"
copyright ="README.TXT;1"
/>
<directory_tree>
<file name="SYSTEM.CNF" type="data" source="${PROJECT_SOURCE_DIR}/system.cnf" />
<file name="PS1BSP.EXE" type="data" source="ps1bsp.exe" />
<file name="PS1BSP.MAP" type="data" source="ps1bsp.map" />
<dummy sectors="1024"/>
</directory_tree>
</track>
<!--<track type="audio" source="track2.wav" />-->
</iso_project>

54
main.c

@ -0,0 +1,54 @@
#include "common.h"
#include "input.h"
#include "display.h"
#include "time.h"
#include "asset.h"
extern u_long tim_e1m1[];
extern u_long tim_e2m2[];
VECTOR cam_pos = { 0, -400, 100 };
SVECTOR cam_rot = { 0 };
// BSP face rendering:
// - Gather vertex data from face start index + length
// - Store vertex data in scratchpad memory (should be plenty of space for one face)
// - Perform camera offset and re-scaling operations to fit vertex data in signed 16-bit fixed point vectors
// - Note: may be possible to (ab)use 32-bit GTE registers & ops to do this calculation and downcast
// - Store rescaled vertex data in scratchpad memory
// Init function
void init(void)
{
time_init();
input_init();
display_init();
asset_loadTexture(tim_e1m1, NULL);
asset_loadTexture(tim_e2m2, NULL);
}
// Main function, program entrypoint
int main(int argc, const char *argv[])
{
// Init stuff
init();
// Main loop
while(1)
{
input_process();
display_start();
// Draw stuff
FntPrint(-1, "Camera pos = (%d, %d, %d) rot = (%d, %d, %d)\n", cam_pos.vx, cam_pos.vy, cam_pos.vz, cam_rot.vx, cam_rot.vy, cam_rot.vz);
FntFlush(-1);
display_finish();
time_tick();
}
return 0;
}

4
system.cnf

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

19
time.c

@ -0,0 +1,19 @@
#include "common.h"
#include "time.h"
static int frameNumber;
void time_init()
{
frameNumber = 0;
}
void time_tick()
{
++frameNumber;
}
int time_getFrameNumber()
{
return frameNumber;
}

9
time.h

@ -0,0 +1,9 @@
#ifndef __TIME_H__
#define __TIME_H__
void time_init();
void time_tick();
int time_getFrameNumber();
#endif // __TIME_H__
Loading…
Cancel
Save