Add STP semi-transparency example
This commit is contained in:
parent
f0472cfce4
commit
7cd46c533a
9
Makefile
9
Makefile
@ -18,6 +18,8 @@ hello_pad:
|
|||||||
$(MAKE) -C hello_pad
|
$(MAKE) -C hello_pad
|
||||||
hello_poly:
|
hello_poly:
|
||||||
$(MAKE) -C hello_poly
|
$(MAKE) -C hello_poly
|
||||||
|
hello_poly_stp:
|
||||||
|
$(MAKE) -C hello_poly_stp
|
||||||
hello_poly_ft:
|
hello_poly_ft:
|
||||||
$(MAKE) -C hello_poly_ft
|
$(MAKE) -C hello_poly_ft
|
||||||
hello_poly_gt:
|
hello_poly_gt:
|
||||||
@ -56,6 +58,7 @@ clean:
|
|||||||
$(MAKE) -C hello_pad clean
|
$(MAKE) -C hello_pad clean
|
||||||
$(MAKE) -C hello_poly clean
|
$(MAKE) -C hello_poly clean
|
||||||
$(MAKE) -C hello_poly_ft clean
|
$(MAKE) -C hello_poly_ft clean
|
||||||
|
$(MAKE) -C hello_poly_stp clean
|
||||||
$(MAKE) -C hello_poly_gt clean
|
$(MAKE) -C hello_poly_gt clean
|
||||||
$(MAKE) -C hello_poly_gt_tw clean
|
$(MAKE) -C hello_poly_gt_tw clean
|
||||||
$(MAKE) -C hello_poly_inline clean
|
$(MAKE) -C hello_poly_inline clean
|
||||||
@ -97,5 +100,9 @@ all:
|
|||||||
$(MAKE) -C hello_str all
|
$(MAKE) -C hello_str all
|
||||||
|
|
||||||
# declare phony rules
|
# 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_sio hello_sprt hello_tile hello_vag hello_world hello_cdda hello_cd hello_xa hello_bs hello_str \
|
.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_sio hello_sprt hello_tile \
|
||||||
|
hello_vag hello_world hello_cdda hello_cd hello_xa hello_bs hello_str \
|
||||||
|
hello_poly_stp \
|
||||||
clean all
|
clean all
|
||||||
|
10
hello_poly_stp/Makefile
Normal file
10
hello_poly_stp/Makefile
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
TARGET = hello_poly_stp
|
||||||
|
|
||||||
|
SRCS = hello_poly_stp.c \
|
||||||
|
TIM/stpOnAlpha.tim \
|
||||||
|
TIM/stpOnAlphaI.tim \
|
||||||
|
TIM/stpOnBlack.tim \
|
||||||
|
TIM/stpOnColIndex.tim \
|
||||||
|
TIM/stpOnNonBlack.tim \
|
||||||
|
|
||||||
|
include ../common.mk
|
58
hello_poly_stp/README.md
Normal file
58
hello_poly_stp/README.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
# STP : Semi-Transparency usage
|
||||||
|
|
||||||
|
This example shows the various way of converting an image with transparency to a TIM and use it in code.
|
||||||
|
It also shows the effect of activating Semi-Transparency on a primitive textured with those images.
|
||||||
|
|
||||||
|
**By default, the PSX will consider black pixels (0,0,0,0) as transparent**.
|
||||||
|
In order to display those black pixels as black, you have to set the STP on black (1,0,0,0).
|
||||||
|
Black pixels and non-black pixels with the STP bit will display as semi-transparent when using `SetSemiTrans()`.
|
||||||
|
|
||||||
|
Use the `SELECT` button to switch primitive semi-transparency on and off.
|
||||||
|
|
||||||
|
It also features a few C struct to facilitate access to the TIM file / pixel data.
|
||||||
|
|
||||||
|
You can use Lameguy64's [img2tim](https://github.com/Lameguy64/img2tim) tool to convert most of image formats to the psx [TIM format.](https://github.com/ABelliqueux/nolibgs_hello_worlds/tree/main/TIM).
|
||||||
|
|
||||||
|
## STP on black
|
||||||
|
|
||||||
|
Use this to display black pixels as black, not transparent.
|
||||||
|
The **inverted** alpha mask of the TIM corresponds to the position of black (0,0,0) pixels in the image.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
img2tim -b -org 640 0 -o stpOnBlack.tim av.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## STP on non-black
|
||||||
|
|
||||||
|
Black pixels will be considered as transparent, and non-black pixels will receive semi-transparency with `SetSemiTrans()`.
|
||||||
|
|
||||||
|
The alpha mask of the TIM corresponds to the position of non-black (n,n,n) pixels in the image.
|
||||||
|
Additionally, a setting allows you to define the RGB value to be considered transparent ; `-tcol` . This does not set any STP flag.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
img2tim -t -org 320 0 -o stpOnNonBlack.tim av.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use alpha channel
|
||||||
|
|
||||||
|
The alpha mask of the TIM corresponds to the existing alpha channel of the image (PNG, GIF, TGA, TIFF).
|
||||||
|
Additionally, a setting allows you to define the threshold for the alpha value to be considered transparent ; `-alpt` . This does not set any STP flag.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
img2tim -usealpha -org 640 256 -o stpOnNonBlack.tim av.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use color index
|
||||||
|
|
||||||
|
When using 8/4bpp palettized images, you can specify the index number of the color to be considered transparent. This does not set any STP flag.
|
||||||
|
|
||||||
|
You can set the STP bit by CLUT color with PsyQ's `TIMTOOL.EXE`. This allows you do do cool stuff like oly having specific colors being rendered as semi-transparent by `SetSemiTrans()`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
img2tim -b -bpp 8 -tindex 0 -org 640 256 -plt 0 481 -o stpOnColIndex.tim av8.png
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black transparency work-around
|
||||||
|
|
||||||
|
Using a pseudo-black color with one of the channels value to 10, i.e : `255,255,10` can be done so you dont have to set the STP bit on full black.
|
||||||
|
This allows you to keep the pseudo-black opaque when using `SetSemiTrans()`.
|
BIN
hello_poly_stp/TIM/stpOnAlpha.tim
Normal file
BIN
hello_poly_stp/TIM/stpOnAlpha.tim
Normal file
Binary file not shown.
BIN
hello_poly_stp/TIM/stpOnAlphaI.tim
Normal file
BIN
hello_poly_stp/TIM/stpOnAlphaI.tim
Normal file
Binary file not shown.
BIN
hello_poly_stp/TIM/stpOnBlack.tim
Normal file
BIN
hello_poly_stp/TIM/stpOnBlack.tim
Normal file
Binary file not shown.
BIN
hello_poly_stp/TIM/stpOnCol.tim
Normal file
BIN
hello_poly_stp/TIM/stpOnCol.tim
Normal file
Binary file not shown.
BIN
hello_poly_stp/TIM/stpOnColIndex.tim
Normal file
BIN
hello_poly_stp/TIM/stpOnColIndex.tim
Normal file
Binary file not shown.
BIN
hello_poly_stp/TIM/stpOnNonBlack.tim
Normal file
BIN
hello_poly_stp/TIM/stpOnNonBlack.tim
Normal file
Binary file not shown.
257
hello_poly_stp/hello_poly_stp.c
Normal file
257
hello_poly_stp/hello_poly_stp.c
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
// Demo the different settings for pixel and primitive semi-transparency
|
||||||
|
//
|
||||||
|
// 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 16 // margins for text display
|
||||||
|
#define MARGINY 16
|
||||||
|
#define FONTSIZE 8 * 8 // 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]; // 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
|
||||||
|
|
||||||
|
|
||||||
|
// RGB pixels are 16bpp, 5b Red, 5b Green, 5b Blue, 1b STP (semi-transparency)
|
||||||
|
// See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.183
|
||||||
|
typedef struct RGB_PIX {
|
||||||
|
u_int R:5, G:5, B:5, STP:1;
|
||||||
|
} RGB_PIX;
|
||||||
|
|
||||||
|
// TIM's pixel data
|
||||||
|
// See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.182
|
||||||
|
typedef struct PIXEL {
|
||||||
|
u_long bnum;
|
||||||
|
u_short DX, DY;
|
||||||
|
u_short W, H;
|
||||||
|
RGB_PIX data[];
|
||||||
|
} PIXEL;
|
||||||
|
|
||||||
|
// TIM's CLUT section - exists only in 4/8bpp TIMs
|
||||||
|
// See See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.181
|
||||||
|
typedef struct CLUT {
|
||||||
|
u_long bnum;
|
||||||
|
u_short DX, DY;
|
||||||
|
u_short W, H;
|
||||||
|
u_short clut[];
|
||||||
|
} CLUT;
|
||||||
|
|
||||||
|
// 4/8bpp TIM files have CLUT
|
||||||
|
typedef struct TIM_FILE_CLUT{
|
||||||
|
u_long ID;
|
||||||
|
u_long flag;
|
||||||
|
u_long clut;
|
||||||
|
PIXEL pixel[];
|
||||||
|
} TIM_FILE_CLUT;
|
||||||
|
|
||||||
|
// 16/24bpp TIM files have not CLUT member
|
||||||
|
// See See http://psx.arthus.net/sdk/Psy-Q/DOCS/FileFormat47.pdf, p.179
|
||||||
|
typedef struct TIM_FILE{
|
||||||
|
u_long ID;
|
||||||
|
u_long flag;
|
||||||
|
PIXEL pixel[];
|
||||||
|
} TIM_FILE;
|
||||||
|
|
||||||
|
// If we were using C++, we could use templates
|
||||||
|
//~ struct EmbeddedClut { u_long clut; };
|
||||||
|
//~ struct NoEmbeddedClut { };
|
||||||
|
//~ template<has_clut>
|
||||||
|
//~ struct TIM_FILE {
|
||||||
|
//~ u_long ID;
|
||||||
|
//~ u_long flag;
|
||||||
|
//~ std::conditional<has_clut, EmbeddedClut, NoEmbeddedClut> clut;
|
||||||
|
//~ PIXEL pixel[];
|
||||||
|
//~ };
|
||||||
|
|
||||||
|
// 16bpp TIM
|
||||||
|
// STP set on black pixels ( STP, B, R, G == 1, 0, 0 ,0)
|
||||||
|
extern TIM_FILE _binary_TIM_stpOnBlack_tim_start;
|
||||||
|
// STP set on non black pixels ( STP, B, R, G == 1, !0, !0 ,!0)
|
||||||
|
extern TIM_FILE _binary_TIM_stpOnNonBlack_tim_start;
|
||||||
|
// STP set on image's alpha channnel ( STP, B, R, G == 1, a, a ,a)
|
||||||
|
extern TIM_FILE _binary_TIM_stpOnAlphaI_tim_start;
|
||||||
|
// STP set on 8bpp TIM's CLUT index 0 ( STP, B, R, G == 1, i, i, i)
|
||||||
|
extern TIM_FILE _binary_TIM_stpOnColIndex_tim_start;
|
||||||
|
// Store in an array so we can iterate over it
|
||||||
|
TIM_FILE * timFiles[4];
|
||||||
|
TIM_IMAGE timImages[4];
|
||||||
|
// Number of primitives to draw
|
||||||
|
#define NUM_PRIM 4
|
||||||
|
// Primitive stp flag : 0 == off, 1 == on
|
||||||
|
char stpFlag = 0;
|
||||||
|
|
||||||
|
void LoadTexture(TIM_FILE * tim, TIM_IMAGE * tparam){ // This part is from Lameguy64's tutorial series : lameguy64.net/svn/pstutorials/chapter1/3-textures.html login/pw: annoyingmous
|
||||||
|
OpenTIM( ( u_long * ) 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( 0 , 0 );
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
SetDispMask(1); // Display on screen
|
||||||
|
setRGB0(&draw[0], 255, 0, 128);
|
||||||
|
setRGB0(&draw[1], 255, 0, 128);
|
||||||
|
draw[0].isbg = 1;
|
||||||
|
draw[1].isbg = 1;
|
||||||
|
PutDispEnv(&disp[db]);
|
||||||
|
PutDrawEnv(&draw[db]);
|
||||||
|
FntLoad(960, 0);
|
||||||
|
FntOpen(MARGINX, MARGINY, SCREENXRES - MARGINX * 2, SCREENXRES - MARGINY * 2, 0, 512 );
|
||||||
|
}
|
||||||
|
void display(void)
|
||||||
|
{
|
||||||
|
DrawSync(0);
|
||||||
|
VSync(0);
|
||||||
|
PutDispEnv(&disp[db]);
|
||||||
|
PutDrawEnv(&draw[db]);
|
||||||
|
DrawOTag(&ot[db][OTLEN - 1]);
|
||||||
|
db = !db;
|
||||||
|
nextpri = primbuff[db];
|
||||||
|
}
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
// Populate array with pointers to TIM data
|
||||||
|
timFiles[0] = &_binary_TIM_stpOnBlack_tim_start;
|
||||||
|
timFiles[1] = &_binary_TIM_stpOnNonBlack_tim_start;
|
||||||
|
timFiles[2] = &_binary_TIM_stpOnAlphaI_tim_start;
|
||||||
|
timFiles[3] = &_binary_TIM_stpOnColIndex_tim_start;
|
||||||
|
// Init Disp/Draw, double buffer, font
|
||||||
|
init();
|
||||||
|
// Init proto pad
|
||||||
|
PadInit(0);
|
||||||
|
int pad, oldPad;
|
||||||
|
POLY_FT4 * poly[4] = {0}; // pointer to a POLY_G4
|
||||||
|
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
|
||||||
|
};
|
||||||
|
VECTOR TransVector = { SCREENXRES/3, SCREENYRES/4, 128, 0}; // Initialize translation vector {x, y, z, pad}
|
||||||
|
SVECTOR RotVector = {0}; // Initialize rotation vector {x, y, z}
|
||||||
|
|
||||||
|
// Load textures to VRAM
|
||||||
|
for (char tim = 0; tim < 4; tim++){
|
||||||
|
LoadTexture(timFiles[tim], &timImages[tim]);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// Clear OT
|
||||||
|
ClearOTagR(ot[db], OTLEN);
|
||||||
|
// Use a temporary work matrix
|
||||||
|
MATRIX Work;
|
||||||
|
// Set Trans/Rot vectors to work matrix
|
||||||
|
RotMatrix(&RotVector, &Work); // Apply rotation matrix
|
||||||
|
TransMatrix(&Work, &TransVector); // Apply translation matrix
|
||||||
|
SetRotMatrix(&Work); // Set default rotation matrix
|
||||||
|
SetTransMatrix(&Work); // Set default transformation matrix
|
||||||
|
// Draw NUM_PRIM primitives
|
||||||
|
for (int i = 0; i < NUM_PRIM; i++){
|
||||||
|
long p, flag;
|
||||||
|
// Draw prims with an offset base on iteration number
|
||||||
|
TransVector.vx = SCREENXRES/NUM_PRIM + (i * (SCREENXRES/NUM_PRIM + 32) ) ;
|
||||||
|
TransVector.vy = SCREENYRES/NUM_PRIM;
|
||||||
|
if ( i >= 2) {
|
||||||
|
TransVector.vx = SCREENXRES/NUM_PRIM + ((i - 2) * (SCREENXRES/NUM_PRIM + 32) ) ;
|
||||||
|
TransVector.vy = SCREENYRES/2 + 24;
|
||||||
|
}
|
||||||
|
TransMatrix(&Work, &TransVector);
|
||||||
|
SetTransMatrix(&Work);
|
||||||
|
// Set poly
|
||||||
|
poly[i] = (POLY_FT4 *)nextpri; // Set poly to point to the address of the next primitiv in the buffer
|
||||||
|
setPolyFT4(poly[i]); // Initialize poly as a POLY_F4
|
||||||
|
// Get texture page
|
||||||
|
poly[i]->tpage = getTPage( timImages[i].mode & 0x3,
|
||||||
|
0,
|
||||||
|
// Get Tpage coordinates from the TIM_IMAGE mode and prect members.
|
||||||
|
timImages[i].prect->x,
|
||||||
|
timImages[i].prect->y);
|
||||||
|
// If 8/4bpp, get CLUT
|
||||||
|
if ( (timImages[i].mode & 0x3) < 2 ) {
|
||||||
|
setClut(poly[i],
|
||||||
|
timImages[i].crect->x,
|
||||||
|
timImages[i].crect->y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setRGB0(poly[i], 128, 128, 128); // Set poly color (neutra here)
|
||||||
|
SetSemiTrans(poly[i], stpFlag);
|
||||||
|
RotTransPers4(
|
||||||
|
&VertPos[0], &VertPos[1], &VertPos[2], &VertPos[3],
|
||||||
|
(long*)&poly[i]->x0, (long*)&poly[i]->x1, (long*)&poly[i]->x2, (long*)&poly[i]->x3,
|
||||||
|
&p,
|
||||||
|
&flag
|
||||||
|
); // Perform coordinate and perspective transformation for 4 vertices
|
||||||
|
setUV4(poly[i], 0, 0, 0, 144, 144, 0, 144, 144); // Set UV coordinates in order Top Left, Bottom Left, Top Right, Bottom Right
|
||||||
|
// Add poly to the Ordering table
|
||||||
|
addPrim(ot[db], poly[i]);
|
||||||
|
// Increment nextpri address with size of a POLY_F4 struct
|
||||||
|
nextpri += sizeof(POLY_FT4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pad input
|
||||||
|
pad = PadRead(0);
|
||||||
|
// If select button is used
|
||||||
|
if ( pad & PADselect && !( pad & oldPad ) ){
|
||||||
|
// Flip STP flag
|
||||||
|
stpFlag = !stpFlag;
|
||||||
|
// Set flag to avoir misfire
|
||||||
|
oldPad = pad;
|
||||||
|
}
|
||||||
|
// Reset flag when button released
|
||||||
|
if (!(pad & PADselect)) {
|
||||||
|
oldPad = 0;
|
||||||
|
}
|
||||||
|
FntPrint("Hello semi-transparency !\nPrim STP (push Select) : %d\n\n\n\n\n\n\n\n\n\n\n\n", stpFlag);
|
||||||
|
FntPrint(" stp on black stp on non-black\n\n\n\n\n\n\n\n\n\n\n\n");
|
||||||
|
FntPrint(" stp on non-black stp on col index");
|
||||||
|
FntFlush(-1);
|
||||||
|
display();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user