Latest compatible version of Classicube from the original GitHub repository (https://github.com/ClassiCube/ClassiCube) that can be compiled on Classicube for PowerMac PPC running Mac OS X 10.4.

This commit is contained in:
Andrei Alexandru
2025-12-17 13:17:57 +02:00
commit c71492f846
1248 changed files with 422858 additions and 0 deletions

25
third_party/gldc/LICENSE vendored Normal file
View File

@@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2018, Luke Benstead
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

26
third_party/gldc/gldc.h vendored Normal file
View File

@@ -0,0 +1,26 @@
#ifndef PRIVATE_H
#define PRIVATE_H
#include <stdint.h>
#define GLDC_FORCE_INLINE __attribute__((always_inline)) inline
#define GLDC_NO_INLINE __attribute__((noinline))
typedef struct {
/* Same 32 byte layout as pvr_vertex_t */
uint32_t flags;
float x, y, w;
uint32_t u, v; // really floats, but stored as uint for better load/store codegen
uint32_t bgra;
float z; // actually oargb, but repurposed since unused
} __attribute__ ((aligned (32))) Vertex;
typedef struct {
uint32_t format;
void *data;
uint16_t width;
uint16_t height;
} TextureObject;
void GLDC_NO_INLINE SubmitCommands(Vertex* v3, int n);
#endif // PRIVATE_H

258
third_party/gldc/sh4.c vendored Normal file
View File

@@ -0,0 +1,258 @@
#include <kos.h>
#include <dc/pvr.h>
#include "gldc.h"
#define PushVertex(src, dst) __asm__ volatile ( \
"fmov.d @%1+, dr0 ! LS, FX = *src, src += 8\n" \
"fmov.d @%1+, dr2 ! LS, YW = *src, src += 8\n" \
"add #64, %0 ! EX, dst += 64\n" \
"fmul fr3, fr3 ! FE, W = W * W\n" \
"fmov.d @%1+, dr4 ! LS, UV = *src, src += 8\n" \
"fmov.d @%1+, dr6 ! LS, C? = *src, src += 8\n" \
"fsrra fr3 ! FE, W = 1/sqrt(W*W) ~ 1/W\n" \
"fmov.d dr6, @-%0 ! LS, dst -= 8, *dst = C?\n" \
"fmov.d dr4, @-%0 ! LS, dst -= 8, *dst = UV\n" \
"fmul fr3, fr2 ! FE, Y = W * Y\n" \
"add #-32, %1 ! EX, src -= 32\n" \
"fmov.d dr2, @-%0 ! LS, dst -= 8, *dst = YW\n" \
"fmul fr3, fr1 ! FE, Y = X * X\n" \
"fmov.d dr0, @-%0 ! LS, dst -= 8, *dst = FX\n" \
"pref @%0 ! LS, flush store queue\n" \
: "+r" (dst) \
: "r" (src) \
: "memory", "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7" \
);
#define PushCommand(src, dst) __asm__ volatile ( \
"fmov.d @%1+, dr0 ! LS, D01 = *src, src += 8\n" \
"fmov.d @%1+, dr2 ! LS, D23 = *src, src += 8\n" \
"fmov.d @%1+, dr4 ! LS, D45 = *src, src += 8\n" \
"fmov.d @%1+, dr6 ! LS, D67 = *src, src += 8\n" \
"add #64, %0 ! EX, dst += 64\n" \
"fmov.d dr6, @-%0 ! LS, dst -= 8, *dst = D67\n" \
"fmov.d dr4, @-%0 ! LS, dst -= 8, *dst = D45\n" \
"fmov.d dr2, @-%0 ! LS, dst -= 8, *dst = D23\n" \
"fmov.d dr0, @-%0 ! LS, dst -= 8, *dst = D01\n" \
"pref @%0 ! LS, flush store queue\n" \
"add #-32, %1 ! EX, src -= 32\n" \
: "+r" (dst) \
: "r" (src) \
: "memory", "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7" \
);
extern void ClipEdge(Vertex* const v1, Vertex* const v2, volatile Vertex* vout, char type);
#define V0_VIS (1 << 0)
#define V1_VIS (1 << 1)
#define V2_VIS (1 << 2)
#define V3_VIS (1 << 3)
#define TYPE_VTX 0xE0 // PVR vertex, data
#define TYPE_EOS 0xF0 // PVR vertex, end of strip
extern void ProcessVertexList(Vertex* v3, int n, void* sq_addr);
void SubmitCommands(Vertex* v3, int n) {
volatile Vertex* dst = (volatile Vertex*)MEM_AREA_SQ_BASE;
Vertex* vEnd = v3 + n;
asm volatile ("fschg"); // swap to 64 bit loads/stores
for (; v3 < vEnd; v3++)
{
// Preload next vertex into memory
__builtin_prefetch(v3 + 1);
switch(v3->flags & 0xFF000000) {
case PVR_CMD_VERTEX_EOL:
break;
case PVR_CMD_VERTEX:
continue;
default:
PushCommand(v3, dst);
continue;
};
// Quads [0, 1, 2, 3] -> Triangles [{0, 1, 2} {2, 3, 0}]
Vertex* const v0 = v3 - 3;
Vertex* const v1 = v3 - 2;
Vertex* const v2 = v3 - 1;
uint8_t mask = v3->flags & 0xFF;
// Check if all vertices visible
if (__builtin_expect(mask == (V0_VIS | V1_VIS | V2_VIS | V3_VIS), 1)) {
// Triangle strip: {1,2,0} {2,0,3}
PushVertex(v1, dst);
PushVertex(v2, dst);
PushVertex(v0, dst);
PushVertex(v3, dst);
continue;
}
// Only some vertices visible
// https://casual-effects.com/research/McGuire2011Clipping/clip.glsl
switch(mask) {
case V0_VIS:
// v0
// / |
// / |
// .....A....B...
// / |
// v3--v2---v1
PushVertex(v0, dst); // v0
ClipEdge(v0, v1, dst++, TYPE_VTX); // B
ClipEdge(v3, v0, dst++, TYPE_EOS); // A
break;
case V1_VIS:
// v1
// / |
// / |
// ....A.....B...
// / |
// v0--v3---v2
ClipEdge(v0, v1, dst++, TYPE_VTX); // A
PushVertex(v1, dst); // v1
ClipEdge(v1, v2, dst++, TYPE_EOS); // B
break;
case V2_VIS:
// v2
// / |
// / |
// ....A.....B...
// / |
// v1--v0---v3
ClipEdge(v1, v2, dst++, TYPE_VTX); // A
PushVertex(v2, dst); // v2
ClipEdge(v2, v3, dst++, TYPE_EOS); // B
break;
case V3_VIS:
// v3
// / |
// / |
// ....A.....B...
// / |
// v2--v1---v0
ClipEdge(v3, v0, dst++, TYPE_VTX); // B
ClipEdge(v2, v3, dst++, TYPE_VTX); // A
PushVertex(v3, dst); // v3
break;
case V0_VIS | V1_VIS:
// v0-----------v1
// \ |
// ....B..........A...
// \ |
// v3-----v2
PushVertex(v1, dst); // v1
ClipEdge(v1, v2, dst++, TYPE_VTX); // A
PushVertex(v0, dst); // v0
ClipEdge(v3, v0, dst++, TYPE_EOS); // B
break;
// case V0_VIS | V2_VIS: degenerate case that should never happen
case V0_VIS | V3_VIS:
// v3-----------v0
// \ |
// ....B..........A...
// \ |
// v2-----v1
ClipEdge(v0, v1, dst++, TYPE_VTX); // A
ClipEdge(v2, v3, dst++, TYPE_VTX); // B
PushVertex(v0, dst); // v0
PushVertex(v3, dst); // v3
break;
case V1_VIS | V2_VIS:
// v1-----------v2
// \ |
// ....B..........A...
// \ |
// v0-----v3
PushVertex(v1, dst); // v1
PushVertex(v2, dst); // v2
ClipEdge(v0, v1, dst++, TYPE_VTX); // B
ClipEdge(v2, v3, dst++, TYPE_EOS); // A
break;
// case V1_VIS | V3_VIS: degenerate case that should never happen
case V2_VIS | V3_VIS:
// v2-----------v3
// \ |
// ....B..........A...
// \ |
// v1-----v0
ClipEdge(v1, v2, dst++, TYPE_VTX); // B
PushVertex(v2, dst); // v2
ClipEdge(v3, v0, dst++, TYPE_VTX); // A
PushVertex(v3, dst); // v3
break;
case V0_VIS | V1_VIS | V2_VIS:
// --v1--
// v0-- --v2
// \ |
// .....B.....A...
// \ |
// v3
// v1,v2,v0 v2,v0,A v0,A,B
PushVertex(v1, dst); // v1
PushVertex(v2, dst); // v2
PushVertex(v0, dst); // v0
ClipEdge(v2, v3, dst++, TYPE_VTX); // A
ClipEdge(v3, v0, dst++, TYPE_EOS); // B
break;
case V0_VIS | V1_VIS | V3_VIS:
// --v0--
// v3-- --v1
// \ |
// .....B.....A...
// \ |
// v2
// v0,v1,v3 v1,v3,A v3,A,B
v3->flags = PVR_CMD_VERTEX;
PushVertex(v0, dst); // v0
PushVertex(v1, dst); // v1
PushVertex(v3, dst); // v3
ClipEdge(v1, v2, dst++, TYPE_VTX); // A
ClipEdge(v2, v3, dst++, TYPE_EOS); // B
break;
case V0_VIS | V2_VIS | V3_VIS:
// --v3--
// v2-- --v0
// \ |
// .....B.....A...
// \ |
// v1
// v3,v0,v2 v0,v2,A v2,A,B
v3->flags = PVR_CMD_VERTEX;
PushVertex(v3, dst); // v3
PushVertex(v0, dst); // v0
PushVertex(v2, dst); // v2
ClipEdge(v0, v1, dst++, TYPE_VTX); // A
ClipEdge(v1, v2, dst++, TYPE_EOS); // B
break;
case V1_VIS | V2_VIS | V3_VIS:
// --v2--
// v1-- --v3
// \ |
// .....B.....A...
// \ |
// v0
// v2,v3,v1 v3,v1,A v1,A,B
v3->flags = PVR_CMD_VERTEX;
PushVertex(v2, dst); // v2
PushVertex(v3, dst); // v3
PushVertex(v1, dst); // v1
ClipEdge(v3, v0, dst++, TYPE_VTX); // A
ClipEdge(v0, v1, dst++, TYPE_EOS); // B
break;
}
}
asm volatile ("fschg"); // swap back to 32 bit loads/stores
}

110
third_party/gldc/state.c vendored Normal file
View File

@@ -0,0 +1,110 @@
#include <dc/pvr.h>
#include "gldc.h"
static TextureObject* TEXTURE_ACTIVE;
static uint8_t DEPTH_TEST_ENABLED;
static uint8_t DEPTH_MASK_ENABLED;
static uint8_t CULLING_ENABLED;
static uint8_t FOG_ENABLED;
static uint8_t ALPHA_TEST_ENABLED;
static uint8_t SCISSOR_TEST_ENABLED;
static uint32_t SHADE_MODEL = PVR_SHADE_GOURAUD;
static uint8_t BLEND_ENABLED;
static uint8_t TEXTURES_ENABLED;
static uint8_t AUTOSORT_ENABLED;
static inline int DimensionFlag(int w) {
switch(w) {
case 16: return 1;
case 32: return 2;
case 64: return 3;
case 128: return 4;
case 256: return 5;
case 512: return 6;
case 1024: return 7;
case 8:
default:
return 0;
}
}
static GLDC_NO_INLINE void apply_poly_header(pvr_poly_hdr_t* dst, int list_type) {
TextureObject* tx1 = TEXTURE_ACTIVE;
int gen_culling = CULLING_ENABLED ? PVR_CULLING_CW : PVR_CULLING_SMALL;
int depth_comp = DEPTH_TEST_ENABLED ? PVR_DEPTHCMP_GEQUAL : PVR_DEPTHCMP_ALWAYS;
int depth_write = DEPTH_MASK_ENABLED ? PVR_DEPTHWRITE_ENABLE : PVR_DEPTHWRITE_DISABLE;
int clip_mode = SCISSOR_TEST_ENABLED ? PVR_USERCLIP_INSIDE : PVR_USERCLIP_DISABLE;
int fog_type = FOG_ENABLED ? PVR_FOG_TABLE : PVR_FOG_DISABLE;
int gen_alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? PVR_ALPHA_ENABLE : PVR_ALPHA_DISABLE;
int blend_src = PVR_BLEND_SRCALPHA;
int blend_dst = PVR_BLEND_INVSRCALPHA;
if (list_type == PVR_LIST_OP_POLY) {
/* Opaque polys are always one/zero */
blend_src = PVR_BLEND_ONE;
blend_dst = PVR_BLEND_ZERO;
} else if (list_type == PVR_LIST_PT_POLY) {
/* Punch-through polys require fixed blending and depth modes */
depth_comp = PVR_DEPTHCMP_LEQUAL;
} else if (list_type == PVR_LIST_TR_POLY && AUTOSORT_ENABLED) {
/* Autosort mode requires this mode for transparent polys */
depth_comp = PVR_DEPTHCMP_GEQUAL;
}
int txr_enable, txr_alpha;
if (!TEXTURES_ENABLED || !tx1) {
/* Disable all texturing to start with */
txr_enable = PVR_TEXTURE_DISABLE;
} else {
txr_alpha = (BLEND_ENABLED || ALPHA_TEST_ENABLED) ? PVR_TXRALPHA_ENABLE : PVR_TXRALPHA_DISABLE;
txr_enable = PVR_TEXTURE_ENABLE;
}
/* The base values for CMD */
dst->cmd = PVR_CMD_POLYHDR;
dst->cmd |= txr_enable << 3;
/* Force bits 18 and 19 on to switch to 6 triangle strips */
dst->cmd |= 0xC0000;
/* Or in the list type, shading type, color and UV formats */
dst->cmd |= (list_type << PVR_TA_CMD_TYPE_SHIFT) & PVR_TA_CMD_TYPE_MASK;
dst->cmd |= (PVR_CLRFMT_ARGBPACKED << PVR_TA_CMD_CLRFMT_SHIFT) & PVR_TA_CMD_CLRFMT_MASK;
dst->cmd |= (SHADE_MODEL << PVR_TA_CMD_SHADE_SHIFT) & PVR_TA_CMD_SHADE_MASK;
dst->cmd |= (PVR_UVFMT_32BIT << PVR_TA_CMD_UVFMT_SHIFT) & PVR_TA_CMD_UVFMT_MASK;
dst->cmd |= (clip_mode << PVR_TA_CMD_USERCLIP_SHIFT) & PVR_TA_CMD_USERCLIP_MASK;
dst->mode1 = (depth_comp << PVR_TA_PM1_DEPTHCMP_SHIFT) & PVR_TA_PM1_DEPTHCMP_MASK;
dst->mode1 |= (gen_culling << PVR_TA_PM1_CULLING_SHIFT) & PVR_TA_PM1_CULLING_MASK;
dst->mode1 |= (depth_write << PVR_TA_PM1_DEPTHWRITE_SHIFT) & PVR_TA_PM1_DEPTHWRITE_MASK;
dst->mode1 |= (txr_enable << PVR_TA_PM1_TXRENABLE_SHIFT) & PVR_TA_PM1_TXRENABLE_MASK;
dst->mode2 = (blend_src << PVR_TA_PM2_SRCBLEND_SHIFT) & PVR_TA_PM2_SRCBLEND_MASK;
dst->mode2 |= (blend_dst << PVR_TA_PM2_DSTBLEND_SHIFT) & PVR_TA_PM2_DSTBLEND_MASK;
dst->mode2 |= (fog_type << PVR_TA_PM2_FOG_SHIFT) & PVR_TA_PM2_FOG_MASK;
dst->mode2 |= (gen_alpha << PVR_TA_PM2_ALPHA_SHIFT) & PVR_TA_PM2_ALPHA_MASK;
if (txr_enable == PVR_TEXTURE_DISABLE) {
dst->mode3 = 0;
} else {
dst->mode2 |= (txr_alpha << PVR_TA_PM2_TXRALPHA_SHIFT) & PVR_TA_PM2_TXRALPHA_MASK;
dst->mode2 |= (PVR_FILTER_NEAREST << PVR_TA_PM2_FILTER_SHIFT) & PVR_TA_PM2_FILTER_MASK;
dst->mode2 |= (PVR_MIPBIAS_NORMAL << PVR_TA_PM2_MIPBIAS_SHIFT) & PVR_TA_PM2_MIPBIAS_MASK;
dst->mode2 |= (PVR_TXRENV_MODULATEALPHA << PVR_TA_PM2_TXRENV_SHIFT) & PVR_TA_PM2_TXRENV_MASK;
dst->mode2 |= (DimensionFlag(tx1->width) << PVR_TA_PM2_USIZE_SHIFT) & PVR_TA_PM2_USIZE_MASK;
dst->mode2 |= (DimensionFlag(tx1->height) << PVR_TA_PM2_VSIZE_SHIFT) & PVR_TA_PM2_VSIZE_MASK;
dst->mode3 = (0 << PVR_TA_PM3_MIPMAP_SHIFT) & PVR_TA_PM3_MIPMAP_MASK;
dst->mode3 |= (tx1->format << PVR_TA_PM3_TXRFMT_SHIFT) & PVR_TA_PM3_TXRFMT_MASK;
dst->mode3 |= ((uint32_t)tx1->data & 0x00fffff8) >> 3;
}
}