From 08de895e8582dbc70b639ae5f511ab9ebfb4d68a Mon Sep 17 00:00:00 2001 From: "U-Lameguy64-LT\\Lameguy64" Date: Mon, 17 Jan 2022 09:13:54 +0800 Subject: Removed old libn00bref.odt document, added tilesasm example, examples in source form now copied on installation, more graphics primitives documented, some changes to readme --- CMakeLists.txt | 2 +- README.md | 57 ++-- changelog.txt | 23 +- doc/LibPSn00b Reference.odt | Bin 150699 -> 152872 bytes doc/libn00bref.odt | Bin 36114 -> 0 bytes examples/graphics/hdtv/main.c | 64 +++-- examples/graphics/tilesasm/CMakeLists.txt | 22 ++ examples/graphics/tilesasm/data.s | 35 +++ examples/graphics/tilesasm/drawtiles.s | 272 +++++++++++++++++++ examples/graphics/tilesasm/iso.xml | 34 +++ examples/graphics/tilesasm/main.c | 425 ++++++++++++++++++++++++++++++ examples/graphics/tilesasm/system.cnf | 4 + examples/graphics/tilesasm/tiles_256.png | Bin 0 -> 9362 bytes examples/graphics/tilesasm/tiles_256.tim | Bin 0 -> 66080 bytes examples/readme.txt | 64 +++++ 15 files changed, 941 insertions(+), 61 deletions(-) delete mode 100644 doc/libn00bref.odt create mode 100644 examples/graphics/tilesasm/CMakeLists.txt create mode 100644 examples/graphics/tilesasm/data.s create mode 100644 examples/graphics/tilesasm/drawtiles.s create mode 100644 examples/graphics/tilesasm/iso.xml create mode 100644 examples/graphics/tilesasm/main.c create mode 100644 examples/graphics/tilesasm/system.cnf create mode 100644 examples/graphics/tilesasm/tiles_256.png create mode 100644 examples/graphics/tilesasm/tiles_256.tim create mode 100644 examples/readme.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 87980a5..3d974a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,7 @@ foreach( endforeach() install( - DIRECTORY doc template + DIRECTORY doc template examples DESTINATION ${CMAKE_INSTALL_DATADIR}/psn00bsdk COMPONENT docs ) diff --git a/README.md b/README.md index a8807df..8363799 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,32 @@ # PSn00bSDK PSn00bSDK is a 100% free and open source SDK project for the original Sony -PlayStation for developing homebrew applications and games for the console -100% freely. This SDK can be used for freeware, commercial, and open source -homebrew projects. - -The SDK is composed mainly of libraries (libpsn00b) and some utilities that -provide a basic framework for developing software for the PlayStation -hardware, the compiler is separate (GCC) and should be acquired from GNU. -The library API is intentionally written to resemble the library API of the -official libraries as closely as possible. This design decision is not only -for familiarity reasons to experienced programmers, but also so that existing -sample code and tutorials would still apply to this SDK, as well as making -the process of porting over existing homebrew originally made with official -SDKs easier with minimal modification, provided it doesn't use libgs. +PlayStation for developing homebrew applications and games for the console. +This SDK may be used for freeware, commercial, and open source homebrew +projects as far as what the SDK currently supports. Out of all the open +source PS1 SDK projects that have come and gone from active development +over the years, PSn00bSDK is arguably the most capable of them all. + +Much of the SDK is merely just a set of libraries (libpsn00b) and some +utilities for converting executables and data files to formats more usable +on the target platform. The compiler used is just the standard GNU GCC +toolchain compiled to target mipsel and has to be acquired separately. +The library API was deliberately written to resemble the library API of the +official libraries as closely as possible not only for familiarity reasons +to experienced programmers but also so that existing sample code and tutorials +that have been written over the years would still apply to this SDK, as well +as making the process of porting over existing homebrew originally made with +official SDKs easier with minimal modificationn provided they do not depend +on libgs. PSn00bSDK is currently a work in progress and cannot really be considered production ready, but what is currently implemented should be enough to -produce some interesting homebrew with the SDK, especially with its extensive +produce some interesting homebrew with the SDK especially with its extensive support for the GPU and GTE hardware. There's no reason not to fully support hardware features of a target platform when said hardware features have been fully documented for years (nocash's PSX specs document in this case). -Most of libpsn00b is written mostly in MIPS assembly, moreso functions that +Most of libpsn00b is written mostly in MIPS assembly more so functions that interface with the hardware. Many of the standard C functions are implemented in custom MIPS assembly instead of equivalents found in the BIOS ROM, for both stability (the BIOS libc implementation of the PlayStation is actually buggy) @@ -88,6 +92,7 @@ building it yourself in the long run. Pre-compiled packages for Debian and Msys2 are being planned however (it is already possible to build installers, DEB and RPM packages through CPack so it's only a matter of time). + ## Examples There are a few examples and complete source code of n00bdemo included in @@ -96,7 +101,7 @@ and contributed example programs are welcome. There's also Lameguy's PlayStation Programming Tutorial Series at http://lameguy64.net/tutorials/pstutorials/ for learning how to program -for the PlayStation. The tutorials should still apply to PSn00bSDK. +for the PlayStation. Much of the tutorials should apply for PSn00bSDK. ## To-do List @@ -119,27 +124,11 @@ for the PlayStation. The tutorials should still apply to PSn00bSDK. * Pad and memory card libraries that don't use the BIOS routines. -## Usage terms (or lack thereof) - -PSn00bSDK falls under the terms and conditions of the Mozilla Public -License. A quick summary of this license is that PSn00bSDK can be used -freely in both free and open source projects and commercial closed source -projects as projects using PSn00bSDK does not necessarily have to follow -the MPL as well. - -If modifications to the SDK were made as part of the development of such -projects that enhance its functionality, such changes must be contributed -back in return. - -Homebrew made with PSn00bSDK may not be released under 'annoyingmous'. Although -there's nothing that would enforce it, this term may as well be ignored despite -it annoying this SDK's author. - ## Credits -Main developer: -* Lameguy64 +Main developer/author/whatever: +* Lameguy64 (John "Lameguy" Wilbert Villamor) Honorable mentions: * ijacquez - helpful suggestions for getting C++ working. diff --git a/changelog.txt b/changelog.txt index 3efa7a0..cb4b2e8 100644 --- a/changelog.txt +++ b/changelog.txt @@ -2,6 +2,27 @@ PSn00bSDK changelog Items that are lower in the log are more recently implemented. +01-17-2022 by Lameguy64: + +* docs: Removed old and incomplete libn00bref.odt document (a percussor of the + LibPSn00b Library Reference document) as it got included into a commit by + accident at some point. + +* examples: Improved description of hdtv example. + +* Examples directory is now copied into share/psn00bsdk directory for both + installation and package building. Build instructions for examples also + included. + +* docs: Removed documentation for SetDrawTPageVal() as the function was removed + ages ago. Added documentation to DR_AREA, DR_TWIN and DR_OFFSET primitives + and their associated macros. + +* examples: Added tilesasm example. + +* Updated readme file. + + 11-19-2021 by spicyjpeg: * libc: Removed STACK_MAX_SIZE and added _mem_init() back. RAM and stack size @@ -137,7 +158,7 @@ Items that are lower in the log are more recently implemented. * Libpsn00b: Added int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t and uint64_t variable types in sys/types.h. -* psxgte: Replaced unsigned int variable types with u_long to further +* psxgpu: Replaced unsigned int variable types with u_long to further improve compatibility with code written for the official Sony SDK and to make my tutorial examples easier to compile on PSn00bSDK. Example programs have been updated to account for this change. diff --git a/doc/LibPSn00b Reference.odt b/doc/LibPSn00b Reference.odt index b7fa52c..c997d2a 100644 Binary files a/doc/LibPSn00b Reference.odt and b/doc/LibPSn00b Reference.odt differ diff --git a/doc/libn00bref.odt b/doc/libn00bref.odt deleted file mode 100644 index 99de092..0000000 Binary files a/doc/libn00bref.odt and /dev/null differ diff --git a/examples/graphics/hdtv/main.c b/examples/graphics/hdtv/main.c index a4dcd79..827b096 100644 --- a/examples/graphics/hdtv/main.c +++ b/examples/graphics/hdtv/main.c @@ -4,33 +4,45 @@ * Full-resolution, Anamorphic Widescreen 3D Example * 2020 - 2021 Meido-Tek Productions / PSn00bSDK Project * - * This example is a modification of the fpscam example demonstrating - * a method for taking advantage of widescreen HDTVs by means of a - * custom 704x480 video mode (as opposed to 640x480) and applying - * anamorphic widescreen aspect correction to a 3D perspective. + * This example is a modification of the fpscam example incorporating + * techniques for taking advantage of wide-screen televisions by means + * of a custom 704x480 video mode (as opposed to 640x480) and applying + * anamorphic aspect correction to a 3D perspective matrix. * - * The extended horizontal resolution guarantees that the picture will - * fill the entire screen of a widescreen television as the more - * conventional 640x480 mode would often show a black border on the sides - * of the picture. However, this extended video mode may cause odd effects - * on some analog television displays, so its recommended to implement this - * extended video mode as an option in your software title. Pixels are still - * not aspect correct however, so widescreen has to be achieved through - * anamorphic means, and is not exactly practical for most 2D graphics. + * The extended horizontal resolution guarantees that the video display + * will fill a wide-screen television in 16:9 mode fully, whereas the more + * conventional 640x480 mode displays black borders on the sides of the + * picture on most wide-screen television sets- notably LCD and Plasma type + * television sets. * - * If you wish to use a lower resolution 240/256 line mode but want to make - * it presentable on a widescreen television, use 384x240 or 384x256 as - * such a resolution would not only fill the entire screen of a widescreen - * but it also has close to aspect correct pixels, which is well suited for - * 2D games. The anamorphic aspect correction demonstrated in this example - * should also work for 320x240/256 modes for 3D games, but prefer to use - * 320x240 resolution. + * However, this extended video mode may cause display problems on some + * analog television sets- such as conventional ratio Sony Trinitron + * televisions if the video display is moved too close to the left of the + * screen. Therefore it is recommended to support this extended video mode + * as an option to ensure compatibility with affected televisions. * - * When using 240/256 line modes, you may want to include an option in your - * software title to enable interlace even though your software title does not - * run in high resolution mode. This helps with compatibility on HDTVs - * immensely and in some cases, improves the image quality on such - * televisions. + * Use of the extended video mode does not provide aspect correct pixels + * for widescreen displays (the extended mode merely displays more columns + * of pixels to fill the side borders of widescreen displays), thus 2D + * bitmap graphics will appear stretched as it would when using a more + * conventional 640x480 display resolution on a wide-screen ratio + * television. + * + * If lower resolution 240/256 line mode is desired whilst being presentable + * on a wide-screen television display, use 384x240 or 384x256 as those + * display resolutions can not only cover the side borders of a wide-screen + * television display but it also provides close to aspect correct pixels + * on such television sets and is well suited for 2D games. The anamorphic + * aspect correction demonstrated in this example can also work on the more + * conventional 320x240/256 modes for 3D games when such resolutions are more + * desired. + * + * When 240/256 line video modes are used, it is highly recommended to + * consider implementing an option to enable interlace even if the software + * title does not run in high resolution mode. This is to provide + * compatibility with digital EDTV or HDTV televisions as some of these + * televisions have issues accepting non-interlaced video signals. On some + * televisions enabling interlace can improve the picture quality. * * Controls: * Up - Look up @@ -43,7 +55,7 @@ * Circle - Strafe right * R1 - Slide up * R2 - Slide down - * L1 - Look at cube + * L1 - Look at cube (tracking) * Select - Exit program (only works with CD loaders) * * @@ -51,6 +63,8 @@ * * Changelog: * + * November 23, 2021 - Improved example description. + * * May 10, 2021 - Variable types updated for psxgpu.h changes. * * November 27, 2020 - Initial version. diff --git a/examples/graphics/tilesasm/CMakeLists.txt b/examples/graphics/tilesasm/CMakeLists.txt new file mode 100644 index 0000000..59ef665 --- /dev/null +++ b/examples/graphics/tilesasm/CMakeLists.txt @@ -0,0 +1,22 @@ +# PSn00bSDK example CMake script +# (C) 2021 spicyjpeg - MPL licensed + +cmake_minimum_required(VERSION 3.20) + +if(NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{PSN00BSDK_LIBS}) + set(CMAKE_TOOLCHAIN_FILE $ENV{PSN00BSDK_LIBS}/cmake/sdk.cmake) +endif() + +project( + tilesasm + LANGUAGES C ASM + VERSION 1.0.0 + DESCRIPTION "PSn00bSDK Tiles drawing with assembly example" + HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk" +) + +file(GLOB _sources *.s *.c) +psn00bsdk_add_executable(tilesasm STATIC ${_sources}) +#psn00bsdk_add_cd_image(tilesasm_iso tilesasm iso.xml DEPENDS tilesasm) + +install(FILES ${PROJECT_BINARY_DIR}/tilesasm.exe TYPE BIN) diff --git a/examples/graphics/tilesasm/data.s b/examples/graphics/tilesasm/data.s new file mode 100644 index 0000000..c64ebbc --- /dev/null +++ b/examples/graphics/tilesasm/data.s @@ -0,0 +1,35 @@ +# +# LibPSn00b Example Programs +# +# Drawing Tile-maps with Assembler Routines +# 2022 Meido-Tek Productions / PSn00bSDK Project +# +# Example by John "Lameguy" Wilbert Villamor (Lameguy64) +# +# This assembler file is used to include the file tiles.tim as an array named +# 'tim_tileset' for use in this example program. Note how the variable name +# itself is leading with an underscore (_) in this file. This is because +# GNU C requires leading underscores for global variables, perhaps to prevent +# function names and variable names from mixing up during the linking stage. + +# Tell assembler that the contents that follow must be in the .data section +.section .data + +# This directive define the 'tim_tileset' label as a global symbol so that +# main.c and other program modules can see this symbol during linking +.global tim_tileset + +# This directive is not really required, but its best to define symbols +# not pointing to program code as an object to help identify it as a +# variable in debuggers +.type tim_tileset, @object + +# The following line defines the variable 'tim_tileset' itself filled with the +# contents of the file 'tiles.tim' by using the .incbin directive +# +# Remember the variable type of a symbol is always governed by how it is +# declared in the C code +# +tim_tileset: + .incbin "../tiles_256.tim" + \ No newline at end of file diff --git a/examples/graphics/tilesasm/drawtiles.s b/examples/graphics/tilesasm/drawtiles.s new file mode 100644 index 0000000..15a0707 --- /dev/null +++ b/examples/graphics/tilesasm/drawtiles.s @@ -0,0 +1,272 @@ +# +# LibPSn00b Example Programs +# +# Drawing Tile-maps with Assembler Routines +# 2022 Meido-Tek Productions / PSn00bSDK Project +# +# Example by John "Lameguy" Wilbert Villamor (Lameguy64) +# +# This file contains the assembler routine DrawTiles which can be called from +# a C or C++ compiled module. The routine makes use of constants and assembler +# macros written in the GNU GAS syntax. +# +# Assembler routines called from C-language modules can freely use registers +# $v0-$v1, $at, $a0-$a3, $t0-$t9 without preserving through stack. Registers +# $s0-$s9, $gp and $fp must be preserved through stack before returning and +# registers $k0-$k1 should not be used for obvious reasons (kernel registers). +# $sp and $ra is used as stack pointer and return address respectively. +# $0 or $zero is constantly zero. +# +# A C caller always passes arguments as 32-bit values on registers $a0 to $a3 +# regardless of the data type specified in the function's C declaration. +# Additional arguments are stored in the stack 16 bytes relative to the stack +# pointer ($sp). To get around the stack being modified in different parts of +# a larger routine the stack pointer would be copied to the frame pointer ($fp) +# and the previous value of the frame pointer would be pushed into stack. This +# way additional arguments may be read anywhere starting from $fp+20 instead. +# +.set noreorder # Disable GAS' annoying nop insertion + +.equ db, 1 # Constants for "emulating" SNASM style structs +.equ dh, 2 +.equ dw, 4 + +# +# TILEDEF struct +# + rs=0 # rs is used to emulate SNASM style structs +.equ TILEDEF_uv , rs # Tile texture coordinate + rs=rs+dh +.equ TILEDEF_clut , rs # Tile CLUT + rs=rs+dh +.equ TILEDEF_pad , rs # Padding + rs=rs+dh +.equ TILEDEF_tpage , rs # Tile tpage + rs=rs+dh +.equ TILEDEF_len , rs # Entry length + +# +# TILEINFO struct (to use as offsets) +# + rs=0 +.equ TILEINFO_window_x , rs # \ + rs=rs+dh # - Window coordinates +.equ TILEINFO_window_y , rs # / + rs=rs+dh +.equ TILEINFO_window_w , rs # \ + rs=rs+dh # - Window size +.equ TILEINFO_window_h , rs # / + rs=rs+dh +.equ TILEINFO_tiles , rs # Pointer to TILEDEF entries + rs=rs+dw +.equ TILEINFO_mapdata , rs # Pointer to map data + rs=rs+dw +.equ TILEINFO_map_w , rs # Map width in tile units + rs=rs+dh +.equ TILEINFO_map_h , rs # Map height in tile units + rs=rs+dh + +# +# TILEPKT struct +# + rs=0 +.equ TILEPKT_tag , rs # Primitive tag + rs=rs+dw +.equ TILEPKT_tpage , rs # tpage packet + rs=rs+dw +.equ TILEPKT_rgbc , rs # Tile color + rs=rs+dw +.equ TILEPKT_x , rs # Tile screen coordinates + rs=rs+dh +.equ TILEPKT_y , rs + rs=rs+dh +.equ TILEPKT_uv , rs # Tile texture coordinates + rs=rs+dh +.equ TILEPKT_clut , rs # Tile CLUT + rs=rs+dh +.equ TILEPKT_len , rs # Packet length + +# addprim Macro +# +# Registers a primitive to a ordering table entry. +# +# Arguments: +# ot - Register name of pointer to ordering table entry +# pri - Pointer to a primitive packet +# len - Size of packet in long words (specify as 0xnn00, ie. 0x2000) +# +# Destroys: +# at, v0, v1 +# +.macro addprim ot,pri,len + .set noat + lw $v0, 0(\ot) # Get OT entry + lui $at, 0x00ff # Mask out the packet length field + or $at, 0xffff + and $v0, $at + lui $v1, \len # Merge packet length + or $v1, $v0 + sw $v1, 0(\pri) # Store updated OT entry to packet + lw $v0, 0(\ot) # Get OT entry + and \pri, $at # Mask out last 8-bits of packet address + lui $at, 0xff00 # Mask out OT entry's address + and $v0, $at + or $v0, \pri # Merge packet address to OT entry + sw $v0, 0(\ot) # Store updated OT entry + .set at +.endm + +# +# Start of text section +# +.section .text + +# DrawTiles Function +# +# Renders a tilemap by generating TILEPKT primitives (combined SPRT_16 and +# DR_TPAGE primitives) and registering it to the specified ordering table. +# The drawing region, tile definitions and the tilemap are specified through +# a TILEINFO struct. +# +# C Declaration: +# extern u_char *DrawTiles(int scroll_x, int scroll_y, +# TILEINFO *info, long *ot, u_char *pri); +# +# Arguments: +# scroll_x - X scrolling offset of tile-map +# scroll_y - Y scrolling offset of tile-map +# info - Pointer to a TILEINFO struct +# ot - Pointer to a ordering table entry +# pri - Pointer to next primitive (placed in stack) +# +# Returns: +# New next primitive pointer value. +# +.global DrawTiles # Declare symbol as global +.type DrawTiles, @function # Declare it as a function +DrawTiles: # Symbol label of function + + addiu $sp, -4 # Push frame pointer (fp) to stack + sw $fp, 0($sp) + move $fp, $sp # Copy stack pointer (sp) to fp + + # Register reference: + # + # t0 - Packet address + # t1 - Map data address + # t2 - Tile X offset + # t3 - Tile Y offset + # t4 - Tile X coordinate backup + # t5 - Tile X loop counter + # t6 - Number of tiles to sort per row + # t7 - Number of tile rows to sort + + lhu $t6, TILEINFO_window_w($a2) # Calculate size of window in tiles + lhu $t7, TILEINFO_window_h($a2) + addi $t6, 15 # So the result will be rounded-up + addi $t7, 15 + srl $t6, 4 # Effectively divide by 16 + srl $t7, 4 + + lw $t0, 20($sp) # Obtain next primitive pointer + + srl $t2, $a0, 4 # Compute map offset in tile units + srl $t3, $a1, 4 + + bgez $a0, .Lno_neg_clip_X # Negative X clip test + sub $v0, $0 , $a0 + move $t2, $0 # Force tile offset to zero + add $v0, 15 # Reduce number of tile columns + srl $v0, 4 + sub $t6, $v0 +.Lno_neg_clip_X: + lhu $v1, TILEINFO_map_w($a2) # Positive X clip test + add $v0, $t2, $t6 + addi $v0, 1 + blt $v0, $v1, .Lno_pos_clip_X + nop + sub $v0, $v1 # Compute how many tiles to clip + sub $t6, $v0 # Reduce number of tile columns +.Lno_pos_clip_X: + bgez $a1, .Lno_neg_clip_Y # Negative Y clip test + sub $v0, $0 , $a1 + move $t3, $0 + add $v0, 15 + srl $v0, 4 + sub $t7, $v0 +.Lno_neg_clip_Y: + lhu $v1, TILEINFO_map_h($a2) # Positive Y clip test + add $v0, $t3, $t7 + addi $v0, 1 + blt $v0, $v1, .Lno_pos_clip_Y + nop + sub $v0, $v1 + sub $t7, $v0 +.Lno_pos_clip_Y: + bltz $t6, .Lno_draw # Exit when no tiles to draw + nop + bltz $t7, .Lno_draw + nop + + lh $v0, TILEINFO_window_x($a2) # Compute pixel coordinates for + sub $a0, $v0, $a0 # tiles based on the scroll offset + sll $v0, $t2, 4 + add $a0, $v0 + lh $v0, TILEINFO_window_y($a2) + sub $a1, $v0, $a1 + sll $v0, $t3, 4 + add $a1, $v0 + move $t4, $a0 + sll $t2, 1 + +.Lloop_y: # Begin of tile row loop + lhu $v0, TILEINFO_map_w($a2) # Get width of tilemap + move $t5, $t6 # n tiles to draw row + mult $t3, $v0 # Multiply Y offset by map width + lw $t1, TILEINFO_mapdata($a2) # Get tilemap address + nop + addu $t1, $t2 # Add X offset to address + mflo $v0 # Get Y offset result + sll $v0, 1 # Multiply by two + addu $t1, $v0 # Add to tile address + +.Lloop_x: # Begin of tile column loop + lhu $v1, 0($t1) # Load tile index + addiu $t1, 2 # Advance to next tile + beq $v1, 0xFFFF, .Lskip_tile # Skip tile if index is 0xFFFF + nop + lw $v0, TILEINFO_tiles($a2) # Get pointer to TILEDEF entries + sll $v1, 3 # Multiply by 8 (size of TILEDEFs) + addu $v1, $v0 # Adjust to tiledefs pointer + lw $v0, TILEDEF_uv($v1) # Obtain UV+CLUT + lhu $v1, TILEDEF_tpage($v1) # Obtain tpage + sw $v0, TILEPKT_uv($t0) # Start constructing packet + lui $v0, 0xE100 # tpage packet code + or $v0, $v1 # Merge tpage bits + sw $v0, TILEPKT_tpage($t0) + sh $a0, TILEPKT_x($t0) # Set tile screen coords + sh $a1, TILEPKT_y($t0) + li $v0, 0x7C7F7F7F # Packet code and color + sw $v0, TILEPKT_rgbc($t0) + addprim $a3, $t0, 0x0400 # Register to OT + addiu $t0, TILEPKT_len # Advance packet pointer +.Lskip_tile: + addi $t5, -1 # Decrement and continue iterating + bgez $t5, .Lloop_x # if non-zero + addiu $a0, 16 # Advance X tile coordinate + + move $a0, $t4 # Restore tile X coordinate + addi $t3, 1 # Increment Y offset + addi $t7, -1 # Decrement and continue iterating + bgez $t7, .Lloop_y # if non-zero + addiu $a1, 16 # Advance Y tile coordinate + +.Lno_draw: + + move $v0, $t0 # Set packet pointer as return value + + lw $fp, 0($sp) # Restore frame pointer and return + jr $ra + addiu $sp, 4 + # DrawTiles + \ No newline at end of file diff --git a/examples/graphics/tilesasm/iso.xml b/examples/graphics/tilesasm/iso.xml new file mode 100644 index 0000000..477c636 --- /dev/null +++ b/examples/graphics/tilesasm/iso.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/graphics/tilesasm/main.c b/examples/graphics/tilesasm/main.c new file mode 100644 index 0000000..7f7c7fe --- /dev/null +++ b/examples/graphics/tilesasm/main.c @@ -0,0 +1,425 @@ +/* + * LibPSn00b Example Programs + * + * Drawing Tile-maps with Assembler Routines + * 2022 Meido-Tek Productions / PSn00bSDK Project + * + * Example by John "Lameguy" Wilbert Villamor (Lameguy64) + * + * Demonstrates the use of assembler code to write a high-speed graphics + * routine that draws a 2D tile-map by generating SPRT_16 primitives. + * The assembler routine is called from a compiled C module in a manner no + * different to calling a C routine... A program written in this manner is + * known as mixed-language programming which includes other programming + * languages, not just assembly. + * + * This example also demonstrates using assembler files to include data files + * into a program as arrays (see 'data.s'). Arguably much more elegant and + * convenient than converting files to C headers like in the old days. + * + * The tile data and drawing is handled in a manner similar to that of the + * tile-map drawing functions in libgs where the map data consists of 16-bit + * words with 0xFFFF being a transparent tile, with each tile entry defined + * by an array of structs specifying the tpage, clut and u,v coordinates for + * each tile number. This provides flexibility with how the tile data will be + * organized in the framebuffer. + * + * Per-pixel clipping of the tile-map is actually not performed by the + * DrawTiles function but rather with DR_AREA primitives. This method + * eliminates code overhead from performing the clipping operations in + * software and thus, yields the fastest possible performance for tile + * sorting. Use of the DR_AREA primitive must be handled with care, as + * setting it beyond the display buffers could overwrite textures and + * CLUT data. + * + * Changelog: + * + * January 16, 2022 - Initial version. + * + * Controls: + * + * D-pad - Scroll tile-map + * L1 (hold) - Move tile-map window with D-pad (must be shrunk first) + * L2 (hold) - Resize tile-map window with D-pad + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Constants for convenience + */ +#define OT_LEN 4 /* Number of ordering table entries */ +#define PKTBUFF_LEN 32768 /* Size of packet buffer (in bytes) */ + +/* Define display/draw environments for double buffering */ +DISPENV disp[2]; +DRAWENV draw[2]; +int db; + +/* Define the ordering table and packet buffer arrays */ +long ot[2][OT_LEN]; +char pkt[2][PKTBUFF_LEN]; + +/* Next packet pointer for primitive generation */ +char *pkt_addr; + +/* Pad data buffer */ +char pad_buff[2][34]; + +/* + * Tile definition structure (to define VRAM coordinates of tiles) + */ +typedef struct _TILEDEF +{ + u_char u,v; // Texture coordinates of tile + u_short clut; // CLUT number of tile + u_short pad; // Padding + u_short tpage; // Texture page number +} TILEDEF; + +/* + * Tile info structure (for drawing function) + */ +typedef struct _TILEINFO +{ + RECT window; // Drawing window of tile info (only cull, not clip) + TILEDEF *tiles; // Pointer to TILEDEF array + u_short *mapdata; // Pointer to 16-bit map data + u_short map_w; // Tile map dimensions + u_short map_h; +} TILEINFO; + +/* Define array of tiledefs */ +TILEDEF tiles[256]; + +/* + * Declarations for data.s + */ +extern u_long tim_tileset[]; + +/* + * Declarations for drawtiles.s + */ +extern u_char *DrawTiles(int scroll_x, int scroll_y, + TILEINFO *info, long *ot, u_char *pri); + +/* + * Init function + */ +void init(void) +{ + TIM_IMAGE tim; + + int i,tx,ty; + + // This not only resets the GPU but it also installs the library's + // ISR subsystem to the kernel + ResetGraph(0); + + // Define display environments, first on top and second on bottom + SetDefDispEnv(&disp[0], 0, 0, 320, 240); + SetDefDispEnv(&disp[1], 0, 240, 320, 240); + + // Define drawing environments, first on bottom and second on top + SetDefDrawEnv(&draw[0], 0, 240, 320, 240); + SetDefDrawEnv(&draw[1], 0, 0, 320, 240); + + // Set and enable clear color + setRGB0(&draw[0], 0, 96, 0); + setRGB0(&draw[1], 0, 96, 0); + draw[0].isbg = 1; + draw[1].isbg = 1; + + // Setup buffer counter, packet pointer and ordering tables + db = 0; + pkt_addr = pkt[db]; + + // Clear ordering tables + ClearOTagR(ot[0], OT_LEN); + ClearOTagR(ot[1], OT_LEN); + + // Load test font + FntLoad(960, 0); + + // Open up a test font text stream of 100 characters + FntOpen(0, 8, 320, 224, 0, 100); + + // Upload tileset TIM + GetTimInfo((u_long*)tim_tileset, &tim); /* Get TIM parameters */ + LoadImage(tim.prect, tim.paddr); /* Upload texture to VRAM */ + if( tim.mode & 0x8 ) /* Upload CLUT if present */ + LoadImage(tim.crect, tim.caddr); + + // Initialize tiledefs with coords to the tileset TIM + i = 0; + for(ty=0; ty<16; ty++) + { + for(tx=0; tx<16; tx++) + { + tiles[i].u = tx<<4; + tiles[i].v = ty<<4; + tiles[i].tpage = getTPage(tim.mode & 3, 0, + tim.prect->x, tim.prect->y); + tiles[i].clut = getClut(tim.crect->x, tim.crect->y); + i++; + } + } + + // Initialize pads + InitPAD(&pad_buff[0][0], 34, &pad_buff[1][0], 34); + StartPAD(); + ChangeClearPAD(0); + +} /* init */ + +/* + * Display function + */ +void display(void) +{ + // Wait for all drawing to complete + DrawSync(0); + + // Wait for vertical sync to cap the logic to 60fps (or 50 in PAL mode) + // and avoid screen tearing + VSync(0); + + // Switch pages + PutDispEnv(&disp[db]); + PutDrawEnv(&draw[db]); + + // Begin drawing of the ordering table + DrawOTag(ot[db]+(OT_LEN-1)); + + // Toggle buffer index + db = !db; + + // Clear next ordering table array + ClearOTagR(ot[db], OT_LEN); + + // Reset packet pointer + pkt_addr = pkt[db]; + + // Enable display output, ResetGraph() disables it by default + SetDispMask(1); + +} /* display */ + +/* + * Initializes a randomly generated tile map + */ +void initdata(u_short *tiledata, int w, int h) +{ + int tx,ty; + + for(ty=0; tyx, rect->y, + rect->x, rect->y+rect->h, + ot[db]); + sortLine(rect->x+rect->w, rect->y, + rect->x+rect->w, rect->y+rect->h, + ot[db]); + sortLine(rect->x, rect->y, + rect->x+rect->w, rect->y, + ot[db]); + sortLine(rect->x, rect->y+rect->h, + rect->x+rect->w, rect->y+rect->h, ot[db]); + +} /* sortBox */ + +/* + * Sorts a draw area primitive for hardware clipping + */ +void sortDrawEnv(RECT *drawarea) +{ + DR_AREA *drawpkt; + + drawpkt = (DR_AREA*)pkt_addr; + setDrawArea(drawpkt, drawarea); + addPrim(ot[db], drawpkt); + pkt_addr += sizeof(DR_AREA); + +} /* sortDrawEnv */ + +/* + * Main function + */ +int main(int argc, const char *argv[]) +{ + u_short *tiledata; + TILEINFO tileinfo; + PADTYPE *pad; + RECT cliprect; + + int i,scroll_x,scroll_y; + + /* Init stuff */ + init(); + + /* Allocate buffer for tile data */ + tiledata = (u_short*)malloc((256*256)<<1); + + /* Generate a random tilemap of values 0-255 */ + initdata(tiledata, 256, 256); + + /* Define the TILEINFO struct */ + tileinfo.window.x = 0; + tileinfo.window.y = 0; + tileinfo.window.w = 320; + tileinfo.window.h = 240; + tileinfo.tiles = tiles; + tileinfo.mapdata = tiledata; + tileinfo.map_w = 256; + tileinfo.map_h = 256; + + /* Main loop */ + scroll_x = 0; + scroll_y = 0; + + while(1) + { + /* Handle inputs */ + pad = (PADTYPE*)&pad_buff[0][0]; + + if( pad->stat == 0 ) + { + if( ( pad->type == 0x4 ) || + ( pad->type == 0x5 ) || + ( pad->type == 0x7 ) ) + { + if( !(pad->btn&PAD_L1) ) /* Window resize */ + { + if( !(pad->btn&PAD_UP) && ( tileinfo.window.y > 0 ) ) + { + tileinfo.window.y--; + } + i = tileinfo.window.y+tileinfo.window.h; + if( !(pad->btn&PAD_DOWN) && ( i < disp[db].disp.h ) ) + { + tileinfo.window.y++; + } + if( !(pad->btn&PAD_LEFT) && ( tileinfo.window.x > 0 ) ) + { + tileinfo.window.x--; + } + i = tileinfo.window.x+tileinfo.window.w; + if( !(pad->btn&PAD_RIGHT) && ( i < disp[db].disp.w ) ) + { + tileinfo.window.x++; + } + } + else if( !(pad->btn&PAD_L2) ) /* Window move */ + { + if( !(pad->btn&PAD_UP) && ( tileinfo.window.h > 0 ) ) + { + tileinfo.window.h--; + } + i = tileinfo.window.y+tileinfo.window.h; + if( !(pad->btn&PAD_DOWN) && ( i < disp[db].disp.h ) ) + { + tileinfo.window.h++; + } + if( !(pad->btn&PAD_LEFT) && ( tileinfo.window.w > 0 ) ) + { + tileinfo.window.w--; + } + i = tileinfo.window.y+tileinfo.window.h; + if( !(pad->btn&PAD_RIGHT) && ( i < disp[db].disp.w ) ) + { + tileinfo.window.w++; + } + } + else /* Scrolling */ + { + if( !(pad->btn&PAD_UP) ) + { + scroll_y-=2; + } + if( !(pad->btn&PAD_DOWN) ) + { + scroll_y+=2; + } + if( !(pad->btn&PAD_LEFT) ) + { + scroll_x-=2; + } + if( !(pad->btn&PAD_RIGHT) ) + { + scroll_x+=2; + } + } + } + } + + /* Draw a box around the tile-map window */ + sortBox(&tileinfo.window); + + /* Sort default clipping (this is processed last) */ + sortDrawEnv(&draw[db].clip); + + /* Sort the tiles */ + pkt_addr = DrawTiles(scroll_x, scroll_y, + &tileinfo, ot[db], pkt_addr); + + /* Sort clipping to the tile window */ + cliprect = tileinfo.window; + cliprect.y += draw[db].clip.y; + sortDrawEnv(&cliprect); + + /* Print stats */ + FntPrint(-1, "X=%d Y=%d\n", scroll_x, scroll_y); + FntPrint(-1, "WINDOW POS. (%d,%d)\n", + tileinfo.window.x, tileinfo.window.y); + FntPrint(-1, "WINDOW SIZE (%d,%d)\n", + tileinfo.window.w, tileinfo.window.h); + FntFlush(-1); + + /* Refresh display */ + display(); + } + + return 0; + +} /* main */ diff --git a/examples/graphics/tilesasm/system.cnf b/examples/graphics/tilesasm/system.cnf new file mode 100644 index 0000000..e221726 --- /dev/null +++ b/examples/graphics/tilesasm/system.cnf @@ -0,0 +1,4 @@ +BOOT=cdrom:\template.exe;1 +TCB=4 +EVENT=10 +STACK=801FFFF0 diff --git a/examples/graphics/tilesasm/tiles_256.png b/examples/graphics/tilesasm/tiles_256.png new file mode 100644 index 0000000..e58c06c Binary files /dev/null and b/examples/graphics/tilesasm/tiles_256.png differ diff --git a/examples/graphics/tilesasm/tiles_256.tim b/examples/graphics/tilesasm/tiles_256.tim new file mode 100644 index 0000000..1bb59bb Binary files /dev/null and b/examples/graphics/tilesasm/tiles_256.tim differ diff --git a/examples/readme.txt b/examples/readme.txt new file mode 100644 index 0000000..80747de --- /dev/null +++ b/examples/readme.txt @@ -0,0 +1,64 @@ +PSn00bSDK Example Programs +2019 - 2022 Meido-Tek Productions / PSn00bSDK Project + +## Building the examples ## + +The instructions below assumes that a mipsel-unknown-elf or mipsel-none-elf GNU +toolchain is installed, CMake and Ninja or make is installed and the PSn00bSDK +libraries and tools are compiled and installed. CMake version must be at least +version 3.20 or newer. + +1. If the examples are in /usr/local/share, copy the directory into your home + directory. + +2. Configure the examples with CMake by running: + + cmake -S . -B ./build -DCMAKE_TOOLCHAIN_FILE= + + must point to the sdk.cmake file provided by the SDK. + Unless you've installed the SDK with a custom path, normally this file is + located in /usr/local/lib/libpsn00b/cmake on *nix style systems or + C:\Program Files\PSn00bSDK\lib\libpsn00b\cmake in Windows. + + If the mipsel toolchain has a different prefix (ie. mipsel-none-elf), specify + -DPSN00BSDK_TARGET= to override the default toolchain prefix. + + If Ninja does not work for you or don't have it installed, pass + -G "Unix Makefiles" (or -G "MSys Makefiles" on Windows) to build using make + instead. + +3. Build the example programs by running: + + cmake --build ./build + + This should create a build directory with a directory structure that mirrors + the parent directory. The directories should contain compiled versions of the + example programs as a PS-EXE or ISO file. + + +## Examples summary ## + +The following list is a brief summary of all the example programs included. +Additional information may be found in the source code of each example. + + beginner/cppdemo Simple demonstration of (dynamic) C++ classes + beginner/hello The obligatory "Hello World" example program + cdrom/cdbrowse File browser using libpsxcd's directory functions + cdrom/cdxa Plays CD-XA audio (XA audio not included) + demos/n00bdemo The premiere demonstration program of PSn00bSDK + graphics/balls Draws colored balls bouncing around the screen + graphics/billboard Demonstrates how to draw 2D sprites in a 3D space + graphics/fpscam First-person perspective camera with look-at + graphics/gte Displays a rotating cube using GTE macros + graphics/hdtv Demonstrates anamorphic widescreen at 704x480 + graphics/render2tex Procedural texture effects using off-screen drawing + graphics/rgb24 Displays a 640x480 24-bit RGB image + graphics/tilesasm Drawing a tile-map with assembly language + io/pads Demonstrates reading controllers via low-level access + lowlevel/cartrom ROM firmware for cheat devices written using GNU GAS + sound/vagsample Demonstrates playing VAG sound files with the SPU + system/childexec Loading a child program and returning to parent + system/console TTY based text console that interrupts gameplay + system/dynlink Demonstrates dynamically linked libraries + system/timer Demonstrates using hardware timers with interrupts + system/tty Using TTY as a remote text console interface \ No newline at end of file -- cgit v1.2.3