Browse Source

Added support for stripped MDL model.

Models are rendered without any 3D transformations but with a bit of faked lighting and animations. Added converted player model file and converted normals lookup table.
master
Nico de Poel 3 years ago
parent
commit
49918efe5f
  1. 1
      CMakeLists.txt
  2. 104
      main.c
  3. BIN
      player.ps1mdl
  4. 162
      ps1anorms.h
  5. 47
      ps1mdl.h
  6. BIN
      shambler128.tim

1
CMakeLists.txt

@ -16,6 +16,7 @@ psn00bsdk_add_executable(template STATIC main.c)
psn00bsdk_target_incbin(template PRIVATE tim_player128 player128.tim) psn00bsdk_target_incbin(template PRIVATE tim_player128 player128.tim)
psn00bsdk_target_incbin(template PRIVATE tim_player16bpp player128-16.tim) psn00bsdk_target_incbin(template PRIVATE tim_player16bpp player128-16.tim)
psn00bsdk_target_incbin(template PRIVATE tim_shambler shambler128.tim) psn00bsdk_target_incbin(template PRIVATE tim_shambler shambler128.tim)
psn00bsdk_target_incbin(template PRIVATE mdl_player player.ps1mdl)
psn00bsdk_add_cd_image( psn00bsdk_add_cd_image(
iso # Target name iso # Target name

104
main.c

@ -21,26 +21,37 @@
#include <psxetc.h> #include <psxetc.h>
#include <psxgte.h> #include <psxgte.h>
#include <psxgpu.h> #include <psxgpu.h>
#include <inline_c.h>
#define OTLEN 8
#include "ps1mdl.h"
#define OTLEN 256
#define NUMVERTEXNORMALS 162
static int anorms[NUMVERTEXNORMALS][3] = {
#include "ps1anorms.h"
};
// Define display/draw environments for double buffering // Define display/draw environments for double buffering
DISPENV disp[2]; DISPENV disp[2];
DRAWENV draw[2]; DRAWENV draw[2];
int db; int db;
u_long ot[2][OTLEN]; // Ordering tables, two arrays for double buffering. These are basically "layers" for drawing.
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.
char primbuff[2][32768]; // Primitive buffer, just a raw buffer of bytes to use as a pool for primitives char primbuff[2][32768]; // Primitive buffer, just a raw buffer of bytes to use as a pool for primitives
char *nextpri; char *nextpri;
extern u_long tim_player128[]; extern u_long tim_player128[];
extern u_long tim_player16bpp[]; extern u_long tim_player16bpp[];
extern u_long tim_shambler[]; extern u_long tim_shambler[];
extern u_long mdl_player[];
TIM_IMAGE playerTex; TIM_IMAGE playerTex;
TIM_IMAGE shamblerTex; TIM_IMAGE shamblerTex;
ps1mdl_t model;
void loadTexture(u_long* tim, TIM_IMAGE* tparam)
void loadTexture(const u_long* tim, TIM_IMAGE* tparam)
{ {
GetTimInfo(tim, tparam); GetTimInfo(tim, tparam);
@ -56,6 +67,22 @@ void loadTexture(u_long* tim, TIM_IMAGE* tparam)
DrawSync(0); DrawSync(0);
} }
void loadModel(const u_long* data, ps1mdl_t *mdl)
{
const char *bytes = (const char*)data;
mdl->header = (ps1mdl_header_t*)bytes;
bytes += sizeof(ps1mdl_header_t);
mdl->texCoords = (ps1mdl_texcoord_t*)bytes;
bytes += sizeof(ps1mdl_texcoord_t) * mdl->header->vertexCount;
mdl->triangles = (ps1mdl_triangle_t*)bytes;
bytes += sizeof(ps1mdl_triangle_t) * mdl->header->triangleCount;
mdl->vertices = (ps1mdl_vertex_t*)bytes;
}
// Init function // Init function
void init(void) void init(void)
{ {
@ -96,6 +123,8 @@ void init(void)
loadTexture(tim_player16bpp, &playerTex); loadTexture(tim_player16bpp, &playerTex);
loadTexture(tim_shambler, &shamblerTex); loadTexture(tim_shambler, &shamblerTex);
loadModel(mdl_player, &model);
// Set texture page for the entire drawing environment. Nice in some cases perhaps, but not what we need. // Set texture page for the entire drawing environment. Nice in some cases perhaps, but not what we need.
//draw[0].tpage = getTPage(playerTex.mode & 0x3, 0, playerTex.prect->x, playerTex.prect->y); //draw[0].tpage = getTPage(playerTex.mode & 0x3, 0, playerTex.prect->x, playerTex.prect->y);
//draw[1].tpage = getTPage(playerTex.mode & 0x3, 0, playerTex.prect->x, playerTex.prect->y); //draw[1].tpage = getTPage(playerTex.mode & 0x3, 0, playerTex.prect->x, playerTex.prect->y);
@ -149,7 +178,7 @@ void addTile(int x, int y, int w, int h, int r, int g, int b)
nextpri += sizeof(TILE); nextpri += sizeof(TILE);
} }
void addColoredTriangle(int x0, int y0, int x1, int y1, int x2, int y2, unsigned int rgb0, unsigned int rgb1, unsigned int rgb2)
void addColoredTriangle(int x0, int y0, int x1, int y1, int x2, int y2, unsigned int rgb0, unsigned int rgb1, unsigned int rgb2, unsigned char depth)
{ {
POLY_G3 *poly = (POLY_G3*)nextpri; POLY_G3 *poly = (POLY_G3*)nextpri;
setPolyG3(poly); setPolyG3(poly);
@ -158,7 +187,7 @@ void addColoredTriangle(int x0, int y0, int x1, int y1, int x2, int y2, unsigned
setRGB1(poly, (rgb1 >> 16) & 0xFF, (rgb1 >> 8) & 0xFF, rgb1 & 0xFF); setRGB1(poly, (rgb1 >> 16) & 0xFF, (rgb1 >> 8) & 0xFF, rgb1 & 0xFF);
setRGB2(poly, (rgb2 >> 16) & 0xFF, (rgb2 >> 8) & 0xFF, rgb2 & 0xFF); setRGB2(poly, (rgb2 >> 16) & 0xFF, (rgb2 >> 8) & 0xFF, rgb2 & 0xFF);
addPrim(ot[db], poly);
addPrim(ot[db] + depth, poly);
nextpri += sizeof(POLY_G3); nextpri += sizeof(POLY_G3);
} }
@ -200,19 +229,80 @@ void addTexturedSprite(int x, int y, int w, int h, TIM_IMAGE *img)
nextpri += sizeof(DR_TPAGE); nextpri += sizeof(DR_TPAGE);
} }
static int normToRGB(const int *norm)
{
int r = ((norm[0] + 4096) >> 5) & 0xFF;
int g = ((norm[1] + 4096) >> 5) & 0xFF;
int b = ((norm[2] + 4096) >> 5) & 0xFF;
return r << 16 | g << 8 | b;
}
static int dot(const int *a, const int *b)
{
int c0 = (a[0] * b[0]) >> 12;
int c1 = (a[1] * b[1]) >> 12;
int c2 = (a[2] * b[2]) >> 12;
return c0 + c1 + c2;
}
static int fakeLight(const int *norm)
{
const int light[3] = { ONE, 0, 0 };
int lit = dot(norm, light) >> 4; // Calculate light intensity and normalize to [-256..255]
lit = lit < 0 ? 0 : lit; // Clamp to [0..255]
lit += 32; // Add some ambient light
lit = lit > 255 ? 255 : lit; // Clamp to [0..255] again
return lit << 16 | lit << 8 | lit;
}
void drawStuff(int counter) void drawStuff(int counter)
{ {
ClearOTagR(ot[db], OTLEN); ClearOTagR(ot[db], OTLEN);
// Print the obligatory hello world and counter to show that the // Print the obligatory hello world and counter to show that the
// program isn't locking up to the last created text stream // program isn't locking up to the last created text stream
FntPrint(-1, "HELLO WORLD\n");
FntPrint(-1, "COUNTER=%d, SIN=%d\n", counter, isin(counter)); FntPrint(-1, "COUNTER=%d, SIN=%d\n", counter, isin(counter));
FntPrint(-1, "Image x %d y %d w %d h %d mode 0x%x\n", playerTex.prect->x, playerTex.prect->y, playerTex.prect->w, playerTex.prect->h, playerTex.mode); FntPrint(-1, "Image x %d y %d w %d h %d mode 0x%x\n", playerTex.prect->x, playerTex.prect->y, playerTex.prect->w, playerTex.prect->h, playerTex.mode);
FntPrint(-1, "Model: %d tris, %d verts\n", model.header->triangleCount, model.header->vertexCount);
// Draw the last created text stream // Draw the last created text stream
FntFlush(-1); FntFlush(-1);
int frameNum = (counter >> 2) % model.header->frameCount;
int vertOffs = frameNum * model.header->vertexCount;
for (int triIdx = 0; triIdx < model.header->triangleCount; ++triIdx)
{
ps1mdl_triangle_t *tri = &model.triangles[triIdx];
ps1mdl_vertex_t *v0 = &model.vertices[tri->vertexIndex[0] + vertOffs];
ps1mdl_vertex_t *v1 = &model.vertices[tri->vertexIndex[1] + vertOffs];
ps1mdl_vertex_t *v2 = &model.vertices[tri->vertexIndex[2] + vertOffs];
// Use normal indices to generate a greyscale value. Good for just giving the polygons some gradients.
unsigned int n0 = v0->normalIndex, n1 = v1->normalIndex, n2 = v2->normalIndex;
unsigned int rgb0 = (n0 << 16) | (n0 << 8) | n0;
unsigned int rgb1 = (n1 << 16) | (n1 << 8) | n1;
unsigned int rgb2 = (n2 << 16) | (n2 << 8) | n2;
// Visualize normals as RGB
rgb0 = normToRGB(anorms[v0->normalIndex]);
rgb1 = normToRGB(anorms[v1->normalIndex]);
rgb2 = normToRGB(anorms[v2->normalIndex]);
// Calculate some actual Lambert shading based on a static light vector
rgb0 = fakeLight(anorms[v0->normalIndex]);
rgb1 = fakeLight(anorms[v1->normalIndex]);
rgb2 = fakeLight(anorms[v2->normalIndex]);
// Normally you'd have GTE do this but we're just going for a quick hack now
unsigned short depth = ((unsigned short)v0->position[1] + (unsigned short)v1->position[1] + (unsigned short)v2->position[1]) / 3;
addColoredTriangle(v0->position[0], 240 - v0->position[2], v1->position[0], 240 - v1->position[2], v2->position[0], 240 - v2->position[2], rgb0, rgb1, rgb2, (unsigned char)depth);
}
return;
int r, g, b; int r, g, b;
lerpcol(255, 255, 0, 255, 0, 0, (icos(counter * 32) + 4096) >> 1, &r, &g, &b); lerpcol(255, 255, 0, 255, 0, 0, (icos(counter * 32) + 4096) >> 1, &r, &g, &b);
@ -221,7 +311,7 @@ void drawStuff(int counter)
lerpcol(0, 255, 255, 0, 255, 0, (icos(counter * 24 + 512) + 4096) >> 1, &r, &g, &b); lerpcol(0, 255, 255, 0, 255, 0, (icos(counter * 24 + 512) + 4096) >> 1, &r, &g, &b);
addTile(128, 160, 48, 48, r, g, b); addTile(128, 160, 48, 48, r, g, b);
addColoredTriangle(260, 140, 220, 220, 300, 220, 0xFF0000, 0x00FF00, 0x0000FF);
addColoredTriangle(260, 140, 220, 220, 300, 220, 0xFF0000, 0x00FF00, 0x0000FF, 0);
addTexturedTriangle(260, 40, 220, 120, 300, 120, 0, 94, 74, 124, 58, 1, &playerTex); addTexturedTriangle(260, 40, 220, 120, 300, 120, 0, 94, 74, 124, 58, 1, &playerTex);
addTexturedSprite(20, 140, 80, 80, &playerTex); addTexturedSprite(20, 140, 80, 80, &playerTex);
addTexturedSprite(80, 40, 154, 114, &shamblerTex); addTexturedSprite(80, 40, 154, 114, &shamblerTex);

BIN
player.ps1mdl

162
ps1anorms.h

@ -0,0 +1,162 @@
{-2153, 0, 3484},
{-1813, 978, 3539},
{-1209, 0, 3913},
{-1265, 2048, 3313},
{-665, 1076, 3895},
{0, 0, 4096},
{0, 3484, 2153},
{-604, 2935, 2792},
{604, 2935, 2792},
{0, 2153, 3484},
{1265, 2048, 3313},
{2153, 0, 3484},
{1209, 0, 3913},
{1813, 978, 3539},
{665, 1076, 3895},
{-2792, 604, 2935},
{-3313, 1265, 2048},
{-2407, 1742, 2818},
{-3484, 2153, 0},
{-3539, 1813, 978},
{-2935, 2792, 604},
{-2818, 2407, 1742},
{-2048, 3313, 1265},
{-978, 3539, 1813},
{-1742, 2818, 2407},
{-2935, 2792, -604},
{-2048, 3313, -1265},
{-2153, 3484, 0},
{0, 3484, -2153},
{-978, 3539, -1813},
{0, 3913, -1209},
{-1076, 3895, -665},
{0, 4096, 0},
{0, 3913, 1209},
{-1076, 3895, 665},
{978, 3539, 1813},
{1076, 3895, 665},
{2048, 3313, 1265},
{978, 3539, -1813},
{1076, 3895, -665},
{2048, 3313, -1265},
{3484, 2153, 0},
{2935, 2792, 604},
{2935, 2792, -604},
{2153, 3484, 0},
{1742, 2818, 2407},
{3539, 1813, 978},
{2818, 2407, 1742},
{3313, 1265, 2048},
{2792, 604, 2935},
{2407, 1742, 2818},
{3913, 1209, 0},
{4096, 0, 0},
{3895, 665, 1076},
{3484, -2153, 0},
{3913, -1209, 0},
{3539, -1813, 978},
{3895, -665, 1076},
{3313, -1265, 2048},
{2792, -604, 2935},
{3484, 0, 2153},
{3539, 1813, -978},
{3313, 1265, -2048},
{3895, 665, -1076},
{2153, 0, -3484},
{2792, 604, -2935},
{2792, -604, -2935},
{3484, 0, -2153},
{3313, -1265, -2048},
{3539, -1813, -978},
{3895, -665, -1076},
{604, 2935, -2792},
{1265, 2048, -3313},
{1742, 2818, -2407},
{1813, 978, -3539},
{2407, 1742, -2818},
{2818, 2407, -1742},
{-604, 2935, -2792},
{-1265, 2048, -3313},
{0, 2153, -3484},
{-2153, 0, -3484},
{-1813, 978, -3539},
{-1209, 0, -3913},
{-665, 1076, -3895},
{0, 0, -4096},
{1209, 0, -3913},
{665, 1076, -3895},
{-1813, -978, -3539},
{-1265, -2048, -3313},
{-665, -1076, -3895},
{0, -3484, -2153},
{-604, -2935, -2792},
{604, -2935, -2792},
{0, -2153, -3484},
{1265, -2048, -3313},
{1813, -978, -3539},
{665, -1076, -3895},
{978, -3539, -1813},
{2048, -3313, -1265},
{1742, -2818, -2407},
{2935, -2792, -604},
{2818, -2407, -1742},
{2407, -1742, -2818},
{0, -3913, -1209},
{0, -4096, 0},
{1076, -3895, -665},
{0, -3484, 2153},
{0, -3913, 1209},
{978, -3539, 1813},
{1076, -3895, 665},
{2048, -3313, 1265},
{2935, -2792, 604},
{2153, -3484, 0},
{-978, -3539, -1813},
{-2048, -3313, -1265},
{-1076, -3895, -665},
{-3484, -2153, 0},
{-2935, -2792, -604},
{-2935, -2792, 604},
{-2153, -3484, 0},
{-2048, -3313, 1265},
{-978, -3539, 1813},
{-1076, -3895, 665},
{-3539, -1813, 978},
{-3313, -1265, 2048},
{-2818, -2407, 1742},
{-2792, -604, 2935},
{-1813, -978, 3539},
{-2407, -1742, 2818},
{-1265, -2048, 3313},
{-604, -2935, 2792},
{-1742, -2818, 2407},
{-665, -1076, 3895},
{1813, -978, 3539},
{665, -1076, 3895},
{1265, -2048, 3313},
{604, -2935, 2792},
{0, -2153, 3484},
{1742, -2818, 2407},
{2407, -1742, 2818},
{2818, -2407, 1742},
{-3913, 1209, 0},
{-3895, 665, 1076},
{-4096, 0, 0},
{-3484, 0, 2153},
{-3913, -1209, 0},
{-3895, -665, 1076},
{-3539, 1813, -978},
{-3895, 665, -1076},
{-3313, 1265, -2048},
{-3539, -1813, -978},
{-3895, -665, -1076},
{-3313, -1265, -2048},
{-2792, 604, -2935},
{-2792, -604, -2935},
{-3484, 0, -2153},
{-2818, 2407, -1742},
{-2407, 1742, -2818},
{-1742, 2818, -2407},
{-1742, -2818, -2407},
{-2407, -1742, -2818},
{-2818, -2407, -1742},

47
ps1mdl.h

@ -0,0 +1,47 @@
#ifndef __PS1MDL_H__
#define __PS1MDL_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
int ident;
int version;
unsigned short vertexCount;
unsigned short triangleCount;
unsigned short frameCount;
} ps1mdl_header_t;
typedef struct
{
char onSeam;
short u, v;
} ps1mdl_texcoord_t;
typedef struct
{
unsigned short vertexIndex[3];
} ps1mdl_triangle_t;
typedef struct
{
unsigned char position[3];
unsigned char normalIndex;
} ps1mdl_vertex_t;
typedef struct
{
ps1mdl_header_t *header;
ps1mdl_texcoord_t *texCoords;
ps1mdl_triangle_t *triangles;
ps1mdl_vertex_t *vertices;
} ps1mdl_t;
#ifdef __cplusplus
}
#endif
#endif // __PS1BSP_H__

BIN
shambler128.tim

Loading…
Cancel
Save