Skip to content

Commit

Permalink
export ps2 icon textures
Browse files Browse the repository at this point in the history
  • Loading branch information
bucanero committed Dec 7, 2024
1 parent 85c34aa commit 6ed1e70
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
TOOLS = src/main
PS1TOOLS= src/ps1main
COMMON = src/util.o src/mcio.o src/ps1card.o src/aes.o
COMMON = src/util.o src/mcio.o src/ps1card.o src/aes.o src/ps2icon.o
DEPS = Makefile

CC = gcc
Expand Down
103 changes: 103 additions & 0 deletions include/ps2icon.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
*
* Copyright (c) 2008 Andreas Weis (http://www.ghulbus-inc.de/)
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

//================================================================================================
// Typedefs and Defines
//================================================================================================

typedef struct
{
char magic[4];
uint16_t padding1; // 0000
uint16_t secondLineOffset;
uint32_t padding2; // 00000000
uint32_t transparencyVal; // 0x00 (clear) to 0x80 (opaque)
uint8_t bgColourUpperLeft[16];
uint8_t bgColourUpperRight[16];
uint8_t bgColourLowerLeft[16];
uint8_t bgColourLowerRight[16];
uint8_t light1Direction[16];
uint8_t light2Direction[16];
uint8_t light3Direction[16];
uint8_t light1RGB[16];
uint8_t light2RGB[16];
uint8_t light3RGB[16];
uint8_t ambientLightRGB[16];
char title[68]; // null terminated, S-JIS
char IconName[64]; // null terminated
char copyIconName[64]; // null terminated
char deleteIconName[64]; // null terminated
uint8_t padding3[512];
} ps2_IconSys_t;

/** File header
*/
typedef struct Icon_Header_t {
unsigned int file_id; ///< reserved; should be: 0x010000 (but does not have to ;) )
unsigned int animation_shapes; ///< number of animation shapes per vertex
unsigned int texture_type; ///< texture type - 0x07: uncompressed, 0x06: uncompresses, 0x0f: RLE compression
unsigned int reserved; ///< reserved; should be: 0x3F800000 (but does not have to ;) )
unsigned int n_vertices; ///< number of vertices; must be a multiple of 3
} Icon_Header;
/** Set of vertex coordinates
* @note The f16_* fields indicate float16 data; divide by 4096.0f to convert to float32;
*/
typedef struct Vertex_Coord_t {
short f16_x; ///< vertex x coordinate in float16
short f16_y; ///< vertex y coordinate in float16
short f16_z; ///< vertex z coordinate in float16
short f16_unknown; ///< unknown; seems to influence lightning?
} Vertex_Coord;
/** Set of texture coordinates
* @note The f16_* fields indicate float16 data; divide by 4096.0f to convert to float32;
*/
typedef struct Texture_Data_t {
short f16_u; ///< vertex u texture coordinate in float16
short f16_v; ///< vertex v texture coordinate in float16
unsigned int color; ///< vertex color (32 bit RGBA)
} Texture_Data;
/** Animation header
*/
typedef struct Animation_Header_t {
unsigned int id_tag; ///< ???
unsigned int frame_length; ///< ???
float anim_speed; ///< ???
unsigned int play_offset; ///< ???
unsigned int n_frames; ///< number of frames in the animation
} Animation_Header;
/** Per-frame animation data
*/
typedef struct Frame_Data_t {
unsigned int shape_id; ///< shape used for this frame
unsigned int n_keys; ///< number of keys corresponding to this frame
} Frame_Data;
/** Per-key animation data
*/
typedef struct Frame_Key_t {
float time; ///< ???
float value; ///< ???
} Frame_Key;

//Get icon data as bytes
uint8_t* getIconPS2(const char* folder, const char* iconfile);
73 changes: 72 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@

#include "mcio.h"
#include "util.h"
#include "ps2icon.h"
#include "svpng.h"

#define PROGRAM_NAME "PS2VMC-TOOL"
#define PROGRAM_VER "1.1.2"
#define PROGRAM_VER "1.2.0"

#define PSV_MAGIC 0x50535600

Expand All @@ -42,6 +44,7 @@ enum ps2vmc_cmd {
CMD_ECC_IMG,
CMD_LIST,
CMD_PSU_EXPORT,
CMD_ICONS_PNG,
CMD_EXTRACT,
CMD_MCFORMAT,
CMD_INJECT,
Expand Down Expand Up @@ -69,6 +72,7 @@ static void print_usage(int argc, char **argv)
printf("\t --ecc-image, -ecc <output filepath>\n");
printf("\t --mc-format\n");
printf("\t --list, -ls <mc path>\n");
printf("\t --icons-png <mc path>\n");
printf("\t --extract-file, -x <mc filepath> <output filepath>\n");
printf("\t --inject-file, -in <input filepath> <mc filepath>\n");
printf("\t --make-directory, -mkdir <mc path>\n");
Expand Down Expand Up @@ -298,6 +302,60 @@ static int cmd_export(const char* path, const char* output)
return dd;
}

static int cmd_export_icons_png(const char* path)
{
int r, fd;
ps2_IconSys_t iconsys;
char filePath[256];
uint8_t* output;
char* fnames[4] = { iconsys.IconName, iconsys.copyIconName, iconsys.deleteIconName, NULL };

if (path[0] == '/') path++;
printf("Exporting '%s' icons...\n", path);

snprintf(filePath, sizeof(filePath), "%s/icon.sys", path);
fd = mcio_mcOpen(filePath, sceMcFileAttrReadable | sceMcFileAttrFile);
if (fd < 0)
return fd;

r = mcio_mcRead(fd, &iconsys, sizeof(ps2_IconSys_t));
if (r != (int)sizeof(ps2_IconSys_t)) {
mcio_mcClose(fd);
return -1001;
}
mcio_mcClose(fd);

printf("- List icon : %s\n", fnames[0]);
printf("- Copy icon : %s\n", fnames[1]);
printf("- Delete icon: %s\n", fnames[2]);

for (int i = 0; i < 3; i++) {
output = getIconPS2(path, fnames[i]);
if (!output) {
return -1002;
}

fnames[3] = strrchr(fnames[i], '.');
if (fnames[3]) {
*fnames[3] = 0;
}

snprintf(filePath, sizeof(filePath), "%.12s_%s.png", path, fnames[i]);

FILE *fh = fopen(filePath, "wb");
if (fh == NULL) {
return -1003;
}

svpng(fh, 128, 128, output, 1);
fclose(fh);

printf("Icon succesfully exported to %s\n", filePath);
}

return 0;
}

static int cmd_mcformat(void)
{
int r;
Expand Down Expand Up @@ -702,6 +760,14 @@ int main(int argc, char **argv)
cmd = CMD_LIST;
cmd_args = &argv[3];
}
else if (!strcmp(argv[2], "--icons-png")) {
if (argc < 3) {
print_usage(argc, argv);
return 1;
}
cmd = CMD_ICONS_PNG;
cmd_args = &argv[3];
}
else if (!strcmp(argv[2], "--extract-file") || !strcmp(argv[2], "-x")) {
if (argc < 4) {
print_usage(argc, argv);
Expand Down Expand Up @@ -814,6 +880,11 @@ int main(int argc, char **argv)
if (r < 0)
printf("Error: can't create image file... (%d)\n", r);
}
else if (cmd == CMD_ICONS_PNG) {
r = cmd_export_icons_png(cmd_args[0]);
if (r < 0)
printf("Error: can't export icons... (%d)\n", r);
}
else if (cmd == CMD_PSU_EXPORT) {
r = cmd_export(cmd_args[0], cmd_args[1]);
if (r < 0)
Expand Down
132 changes: 132 additions & 0 deletions src/ps2icon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>

#include "ps2icon.h"
#include "mcio.h"


static uint32_t TIM2RGBA(const uint8_t *buf)
{
uint8_t RGBA[4];
uint16_t lRGB = (int16_t) (buf[1] << 8) | buf[0];

RGBA[0] = 8 * (lRGB & 0x1F);
RGBA[1] = 8 * ((lRGB >> 5) & 0x1F);
RGBA[2] = 8 * (lRGB >> 10);
RGBA[3] = 0xFF;

return *((uint32_t *) &RGBA);
}

static void* ps2IconTexture(const uint8_t* iData)
{
uint32_t i;
uint16_t j;
Icon_Header header;
Animation_Header anim_header;
Frame_Data animation;
uint32_t *lTexturePtr, *lRGBA;

lTexturePtr = (uint32_t *) calloc(128 * 128, sizeof(uint32_t));

//read header:
memcpy(&header, iData, sizeof(Icon_Header));
iData += sizeof(Icon_Header);

//n_vertices has to be divisible by three, that's for sure:
if(header.file_id != 0x010000 || header.n_vertices % 3 != 0)
return lTexturePtr;

//read icon data from file: https://ghulbus-inc.de/projects/ps2iconsys/
///Vertex data
// each vertex consists of animation_shapes tuples for vertex coordinates,
// followed by one vertex coordinate tuple for normal coordinates
// followed by one texture data tuple for texture coordinates and color
for(i=0; i<header.n_vertices; i++) {
iData += sizeof(Vertex_Coord) * header.animation_shapes;
iData += sizeof(Vertex_Coord);
iData += sizeof(Texture_Data);
}

//animation data
// preceeded by an animation header, there is a frame data/key set for every frame:
memcpy(&anim_header, iData, sizeof(Animation_Header));
iData += sizeof(Animation_Header);

//read animation data:
for(i=0; i<anim_header.n_frames; i++) {
memcpy(&animation, iData, sizeof(Frame_Data));
iData += sizeof(Frame_Data);

if(animation.n_keys > 0)
iData += sizeof(Frame_Key) * animation.n_keys;
}

lRGBA = lTexturePtr;

if (header.texture_type <= 7)
{ // Uncompressed texture
for (i = 0; i < (128 * 128); i++)
{
*lRGBA = TIM2RGBA(iData);
lRGBA++;
iData += 2;
}
}
else
{ //Compressed texture
iData += 4;
do
{
j = (int16_t) (iData[1] << 8) | iData[0];
if (0xFF00 == (j & 0xFF00))
{
for (j = (0x0000 - j) & 0xFFFF; j > 0; j--)
{
iData += 2;
*lRGBA = TIM2RGBA(iData);
lRGBA++;
}
}
else
{
iData += 2;
for (; j > 0; j--)
{
*lRGBA = TIM2RGBA(iData);
lRGBA++;
}
}
iData += 2;
} while ((lRGBA - lTexturePtr) < 0x4000);
}

return (lTexturePtr);
}

//Get icon data as bytes
uint8_t* getIconPS2(const char* folder, const char* iconfile)
{
int fd;
uint8_t *buf, *out;
char filePath[256];
struct io_dirent st;

snprintf(filePath, sizeof(filePath), "%s/%s", folder, iconfile);
mcio_mcStat(filePath, &st);

fd = mcio_mcOpen(filePath, sceMcFileAttrReadable | sceMcFileAttrFile);
if (fd < 0)
return calloc(128 * 128, sizeof(uint32_t));

buf = malloc(st.stat.size);
mcio_mcRead(fd, buf, st.stat.size);
mcio_mcClose(fd);

out = ps2IconTexture(buf);
free(buf);

return out;
}

0 comments on commit 6ed1e70

Please # to comment.