mirror of
https://github.com/aap/librw.git
synced 2026-08-10 09:37:04 +01:00
added simple demoreel and ps2 skeleton coded by claude fable 5
This commit is contained in:
@@ -142,6 +142,7 @@ project "librw"
|
||||
filter { "platforms:ps2" }
|
||||
files { "src/ps2/vu1/*.dsm" }
|
||||
|
||||
|
||||
project "dumprwtree"
|
||||
kind "ConsoleApp"
|
||||
targetdir (Bindir)
|
||||
@@ -263,6 +264,14 @@ project "im3d"
|
||||
removeplatforms { "*null" }
|
||||
removeplatforms { "ps2" }
|
||||
|
||||
project "demoreel"
|
||||
kind "WindowedApp"
|
||||
characterset ("MBCS")
|
||||
skeltool("demoreel")
|
||||
entrypoint("WinMainCRTStartup")
|
||||
removeplatforms { "*null" }
|
||||
removeplatforms { "ps2" } -- for now
|
||||
|
||||
project "ska2anm"
|
||||
kind "ConsoleApp"
|
||||
characterset ("MBCS")
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
#ifdef RW_PS2
|
||||
|
||||
//#define SKEL_CDROM
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <eekernel.h>
|
||||
#include <sifdev.h>
|
||||
#include <sifrpc.h>
|
||||
#include <libpad.h>
|
||||
#ifdef SKEL_CDROM
|
||||
#include <libcdvd.h>
|
||||
#endif
|
||||
|
||||
#include <rw.h>
|
||||
#include "skeleton.h"
|
||||
|
||||
using namespace sk;
|
||||
using namespace rw;
|
||||
|
||||
// timer functions from the ps2 driver
|
||||
void StartTime(void);
|
||||
int GetTime(void);
|
||||
float GetTimeF(void);
|
||||
|
||||
/*
|
||||
* Pad
|
||||
*/
|
||||
|
||||
struct PadData
|
||||
{
|
||||
union {
|
||||
unsigned short bits;
|
||||
struct {
|
||||
unsigned short l2 : 1;
|
||||
unsigned short r2 : 1;
|
||||
unsigned short l1 : 1;
|
||||
unsigned short r1 : 1;
|
||||
unsigned short triangle : 1;
|
||||
unsigned short circle : 1;
|
||||
unsigned short cross : 1;
|
||||
unsigned short square : 1;
|
||||
unsigned short select : 1;
|
||||
unsigned short l3 : 1;
|
||||
unsigned short r3 : 1;
|
||||
unsigned short start : 1;
|
||||
unsigned short Dup : 1;
|
||||
unsigned short Dright : 1;
|
||||
unsigned short Ddown : 1;
|
||||
unsigned short Dleft : 1;
|
||||
};
|
||||
};
|
||||
/* down/right is positive */
|
||||
float rX, rY;
|
||||
float lX, lY;
|
||||
};
|
||||
|
||||
struct Pad
|
||||
{
|
||||
PadData prev, now;
|
||||
PadData rising, falling;
|
||||
};
|
||||
|
||||
static bool gotPadirx;
|
||||
static Pad pad;
|
||||
static u_long128 pad_dma_buf[scePadDmaBufferMax] __attribute__((aligned(64)));
|
||||
|
||||
#define EPSILON 0.2f
|
||||
|
||||
static float
|
||||
PadAnalog(int x)
|
||||
{
|
||||
float f = (x/255.0f - 0.5f)*2.0f;
|
||||
if(f > EPSILON) return (f-EPSILON)/(1.0f-EPSILON);
|
||||
if(f < -EPSILON) return (f+EPSILON)/(1.0f-EPSILON);
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static void
|
||||
ReadPad(PadData *pd)
|
||||
{
|
||||
u_char rdata[32];
|
||||
|
||||
if(gotPadirx && scePadRead(0, 0, rdata) > 0){
|
||||
pd->bits = 0xFFFF ^ ((rdata[2] << 8) | rdata[3]);
|
||||
if(rdata[1] == 0x73){
|
||||
pd->rX = PadAnalog(rdata[4]);
|
||||
pd->rY = PadAnalog(rdata[5]);
|
||||
pd->lX = PadAnalog(rdata[6]);
|
||||
pd->lY = PadAnalog(rdata[7]);
|
||||
}else{
|
||||
pd->rX = pd->rY = 0.0f;
|
||||
pd->lX = pd->lY = 0.0f;
|
||||
}
|
||||
}else
|
||||
pd->bits = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
UpdatePad(Pad *p)
|
||||
{
|
||||
p->prev = p->now;
|
||||
ReadPad(&p->now);
|
||||
p->rising = p->now;
|
||||
p->rising.bits &= ~p->prev.bits;
|
||||
p->falling = p->prev;
|
||||
p->falling.bits &= ~p->now.bits;
|
||||
}
|
||||
|
||||
static void
|
||||
InitPad(void)
|
||||
{
|
||||
if(gotPadirx){
|
||||
scePadInit(0);
|
||||
scePadPortOpen(0, 0, pad_dma_buf);
|
||||
}
|
||||
}
|
||||
|
||||
// translate pad buttons to key events so apps
|
||||
// written against the keyboard interface just work
|
||||
static const struct {
|
||||
unsigned short mask;
|
||||
int key;
|
||||
} padkeymap[] = {
|
||||
{ 0x8000, KEY_LEFT }, // Dleft
|
||||
{ 0x4000, KEY_DOWN }, // Ddown
|
||||
{ 0x2000, KEY_RIGHT }, // Dright
|
||||
{ 0x1000, KEY_UP }, // Dup
|
||||
{ 0x0040, ' ' }, // cross
|
||||
{ 0x0020, KEY_ENTER }, // circle
|
||||
{ 0x0080, KEY_TAB }, // square
|
||||
{ 0x0010, KEY_ESC }, // triangle
|
||||
{ 0x0004, KEY_PGUP }, // l1
|
||||
{ 0x0008, KEY_PGDN }, // r1
|
||||
{ 0x0800, KEY_ENTER }, // start
|
||||
};
|
||||
|
||||
static void
|
||||
PadEvents(void)
|
||||
{
|
||||
int i, key;
|
||||
|
||||
UpdatePad(&pad);
|
||||
for(i = 0; i < (int)(sizeof(padkeymap)/sizeof(padkeymap[0])); i++){
|
||||
key = padkeymap[i].key;
|
||||
if(pad.rising.bits & padkeymap[i].mask)
|
||||
EventHandler(KEYDOWN, &key);
|
||||
if(pad.falling.bits & padkeymap[i].mask)
|
||||
EventHandler(KEYUP, &key);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* IOP modules
|
||||
*/
|
||||
|
||||
static char*
|
||||
GetModulePath(char *dst, const char *module)
|
||||
{
|
||||
#ifdef SKEL_CDROM
|
||||
char *p;
|
||||
sprintf(dst, "cdrom0:\\MODULES\\%s;1", module);
|
||||
for(p = dst+7; *p; p++)
|
||||
if(islower(*p))
|
||||
*p = toupper(*p);
|
||||
#else
|
||||
sprintf(dst, "host0:/usr/local/sce/iop/modules/%s", module);
|
||||
#endif
|
||||
return dst;
|
||||
}
|
||||
|
||||
static void
|
||||
LoadModules(void)
|
||||
{
|
||||
char buf[128];
|
||||
int i;
|
||||
|
||||
gotPadirx = true;
|
||||
for(i = 0; i < 10; i++)
|
||||
if(sceSifLoadModule(GetModulePath(buf, "sio2man.irx"), 0, NULL) >= 0)
|
||||
goto sio2ok;
|
||||
printf("can't load module sio2man\n");
|
||||
gotPadirx = false;
|
||||
return;
|
||||
sio2ok:
|
||||
for(i = 0; i < 10; i++)
|
||||
if(sceSifLoadModule(GetModulePath(buf, "padman.irx"), 0, NULL) >= 0)
|
||||
return;
|
||||
printf("can't load module padman\n");
|
||||
gotPadirx = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main loop
|
||||
*/
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
float timeDelta, drawTime, synchTime;
|
||||
int frame;
|
||||
|
||||
args.argc = argc;
|
||||
args.argv = argv;
|
||||
|
||||
sceSifInitRpc(0);
|
||||
#ifdef SKEL_CDROM
|
||||
while(!sceSifRebootIop("cdrom0:\\MODULES\\" IOP_IMAGE_FILE ";1"));
|
||||
while(!sceSifSyncIop());
|
||||
sceSifInitRpc(0);
|
||||
sceSifLoadFileReset();
|
||||
sceCdInit(SCECdINIT);
|
||||
sceCdMmode(SCECdCD);
|
||||
sceFsReset();
|
||||
sceSifInitIopHeap();
|
||||
#endif
|
||||
LoadModules();
|
||||
InitPad();
|
||||
|
||||
if(EventHandler(INITIALIZE, nil) == EVENTERROR)
|
||||
return 0;
|
||||
|
||||
if(EventHandler(RWINITIALIZE, nil) == EVENTERROR)
|
||||
return 0;
|
||||
|
||||
timeDelta = 1.0f/60.0f;
|
||||
frame = 0;
|
||||
while(!sk::globals.quit){
|
||||
StartTime();
|
||||
|
||||
rw::ps2::beginFrame(frame);
|
||||
|
||||
PadEvents();
|
||||
|
||||
EventHandler(IDLE, &timeDelta);
|
||||
|
||||
rw::ps2::endFrame(&drawTime, &synchTime);
|
||||
|
||||
timeDelta = GetTimeF()*0.001f;
|
||||
frame++;
|
||||
}
|
||||
|
||||
EventHandler(RWTERMINATE, nil);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
namespace sk {
|
||||
|
||||
// no window to move the pointer in
|
||||
void
|
||||
SetMousePosition(int x, int y)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -167,9 +167,11 @@ EventStatus
|
||||
EventHandler(Event e, void *param)
|
||||
{
|
||||
EventStatus s;
|
||||
#ifndef RW_PS2
|
||||
if (e == INITIALIZE) {
|
||||
ImGui::CreateContext();
|
||||
}
|
||||
#endif
|
||||
|
||||
s = AppEventHandler(e, param);
|
||||
if(e == QUIT){
|
||||
|
||||
@@ -118,5 +118,7 @@ EventStatus EventHandler(Event e, void *param);
|
||||
|
||||
sk::EventStatus AppEventHandler(sk::Event e, void *param);
|
||||
|
||||
#ifndef RW_PS2
|
||||
#include "imgui/imgui.h"
|
||||
#include "imgui/imgui_impl_rw.h"
|
||||
#endif
|
||||
|
||||
@@ -89,6 +89,15 @@ mult(const Quat &q, const Quat &p)
|
||||
q.w*p.z + q.z*p.w + q.x*p.y - q.y*p.x);
|
||||
}
|
||||
|
||||
Quat
|
||||
cross(const Quat &q, const Quat &p)
|
||||
{
|
||||
return makeQuat(0.0f,
|
||||
q.x*p.w + q.y*p.z - q.z*p.y,
|
||||
q.y*p.w + q.z*p.x - q.x*p.z,
|
||||
q.z*p.w + q.x*p.y - q.y*p.x);
|
||||
}
|
||||
|
||||
|
||||
Quat*
|
||||
Quat::rotate(const V3d *axis, float32 angle, CombineOp op)
|
||||
@@ -108,6 +117,30 @@ Quat::rotate(const V3d *axis, float32 angle, CombineOp op)
|
||||
return this;
|
||||
}
|
||||
|
||||
inline Quat quat(float32 w=1.0f, float32 x=0.0f, float32 y=0.0f, float32 z=0.0f) { return makeQuat(w, x, y, z); }
|
||||
|
||||
Quat
|
||||
exp(const Quat &q)
|
||||
{
|
||||
Quat qv = qvec(q);
|
||||
float32 l = norm(qv);
|
||||
if(l == 0.0f)
|
||||
return quat(expf(q.w));
|
||||
return scale(add(quat(cosf(l)), scale(qv, sinf(l)/l)), expf(q.w));
|
||||
}
|
||||
|
||||
Quat
|
||||
log(const Quat &q)
|
||||
{
|
||||
float32 l = norm(q);
|
||||
Quat p = scale(q, 1.0f/l);
|
||||
float32 c = p.w; p.w = 0.0f;
|
||||
float32 s = norm(p);
|
||||
if(s == 0)
|
||||
return quat(logf(l));
|
||||
return add(quat(logf(l)), scale(p, atan2f(s,c)/s));
|
||||
}
|
||||
|
||||
Quat
|
||||
lerp(const Quat &q, const Quat &p, float32 r)
|
||||
{
|
||||
|
||||
+3
-1
@@ -7,7 +7,9 @@
|
||||
#elif defined(LIBRW_GLFW)
|
||||
#include <GLFW/glfw3.h>
|
||||
#else
|
||||
not implemented
|
||||
// sane fallback
|
||||
#define LIBRW_GLFW
|
||||
#include <GLFW/glfw3.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ writePNG(Image *image, const char *filename)
|
||||
lodepng_state_init(&state);
|
||||
|
||||
pixels = image->pixels;
|
||||
int depth = image->depth;
|
||||
switch(image->depth){
|
||||
case 4:
|
||||
state.info_raw.bitdepth = 4;
|
||||
@@ -125,6 +126,7 @@ writePNG(Image *image, const char *filename)
|
||||
// Don't think we can have 16 bits with PNG
|
||||
// TODO: don't change original image
|
||||
image->convertTo32();
|
||||
pixels = image->pixels;
|
||||
break;
|
||||
case 24:
|
||||
state.info_raw.colortype = LCT_RGB;
|
||||
|
||||
+43
-1
@@ -513,7 +513,7 @@ InitGSregs(void)
|
||||
{
|
||||
uint128 tmp;
|
||||
|
||||
int nregs = 3;
|
||||
int nregs = 4;
|
||||
MAKEQ(tmp, VIFdirect + nregs+1, VIFnop, 0, DMAcnt + nregs+1);
|
||||
vifPacket[vifPacksz++].q_u128 = tmp;
|
||||
MAKE128(tmp, 0xe, SCE_GIF_SET_TAG(nregs, 1, 0,0, SCE_GIF_PACKED, 1));
|
||||
@@ -524,6 +524,9 @@ InitGSregs(void)
|
||||
vifPacket[vifPacksz++].q_u128 = tmp;
|
||||
MAKE128(tmp, SCE_GS_PRMODE, gsRegs.prmode);
|
||||
vifPacket[vifPacksz++].q_u128 = tmp;
|
||||
// clamp additive blending instead of wrapping around
|
||||
MAKE128(tmp, SCE_GS_COLCLAMP, 1);
|
||||
vifPacket[vifPacksz++].q_u128 = tmp;
|
||||
}
|
||||
|
||||
// cannot blend with color at all
|
||||
@@ -1155,6 +1158,34 @@ deviceSystem(DeviceReq req, void *arg, int32 n)
|
||||
// after plugins are constructed
|
||||
break;
|
||||
|
||||
// there's only one of everything
|
||||
case DEVICEGETNUMSUBSYSTEMS:
|
||||
return 1;
|
||||
case DEVICEGETCURRENTSUBSYSTEM:
|
||||
return 0;
|
||||
case DEVICESETSUBSYSTEM:
|
||||
return 1;
|
||||
case DEVICEGETSUBSSYSTEMINFO: {
|
||||
SubSystemInfo *info = (SubSystemInfo*)arg;
|
||||
strncpy(info->name, "PlayStation 2", sizeof(info->name));
|
||||
return 1;
|
||||
}
|
||||
|
||||
case DEVICEGETNUMVIDEOMODES:
|
||||
return 1;
|
||||
case DEVICEGETCURRENTVIDEOMODE:
|
||||
return 0;
|
||||
case DEVICESETVIDEOMODE:
|
||||
return n == 0;
|
||||
case DEVICEGETVIDEOMODEINFO: {
|
||||
VideoMode *mode = (VideoMode*)arg;
|
||||
mode->width = SCREEN_WIDTH;
|
||||
mode->height = SCREEN_HEIGHT;
|
||||
mode->depth = 32;
|
||||
mode->flags = VIDEOMODEEXCLUSIVE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
default:
|
||||
printf("system request %d not implemented\n", req);
|
||||
return 0;
|
||||
@@ -1174,6 +1205,17 @@ beginFrame(int frame)
|
||||
void
|
||||
endFrame(float *t1, float *t2)
|
||||
{
|
||||
uint128 tmp;
|
||||
|
||||
// send a FINISH at the end of the frame so the
|
||||
// interrupt handler can record the finish time
|
||||
MAKEQ(tmp, VIFdirect + 2, VIFnop, 0, DMAcnt + 2);
|
||||
vifPacket[vifPacksz++].q_u128 = tmp;
|
||||
MAKE128(tmp, 0xe, SCE_GIF_SET_TAG(1, 1, 0,0, SCE_GIF_PACKED, 1));
|
||||
vifPacket[vifPacksz++].q_u128 = tmp;
|
||||
MAKE128(tmp, SCE_GS_FINISH, 0);
|
||||
vifPacket[vifPacksz++].q_u128 = tmp;
|
||||
|
||||
sceGsSyncPath(0, 0);
|
||||
*t1 = GetTimeF();
|
||||
// we could start uploading textures here now so they'll be ready after vsynch
|
||||
|
||||
+28
-4
@@ -290,15 +290,39 @@ inline Quat makeQuat(float32 w, const V3d &vec) { return makeQuat(w, vec.x, vec.
|
||||
inline Quat add(const Quat &q, const Quat &p) { return makeQuat(q.w+p.w, q.x+p.x, q.y+p.y, q.z+p.z); }
|
||||
inline Quat sub(const Quat &q, const Quat &p) { return makeQuat(q.w-p.w, q.x-p.x, q.y-p.y, q.z-p.z); }
|
||||
inline Quat negate(const Quat &q) { return makeQuat(-q.w, -q.x, -q.y, -q.z); }
|
||||
inline float32 dot(const Quat &q, const Quat &p) { return q.w*p.w + q.x*p.x + q.y*p.y + q.z*p.z; }
|
||||
inline Quat qvec(const Quat &q) { return makeQuat(0.0f, q.x, q.y, q.z); }
|
||||
inline Quat scale(const Quat &q, float32 r) { return makeQuat(q.w*r, q.x*r, q.y*r, q.z*r); }
|
||||
inline float32 length(const Quat &q) { return sqrtf(q.w*q.w + q.x*q.x + q.y*q.y + q.z*q.z); }
|
||||
inline Quat normalize(const Quat &q) { return scale(q, 1.0f/length(q)); }
|
||||
inline float32 normsq(const Quat &q) { return q.w*q.w + q.x*q.x + q.y*q.y + q.z*q.z; }
|
||||
inline float32 norm(const Quat &q) { return sqrtf(normsq(q)); }
|
||||
inline Quat normalize(const Quat &q) { return scale(q, 1.0f/norm(q)); }
|
||||
inline float32 length(const Quat &q) { return norm(q); }
|
||||
inline Quat conj(const Quat &q) { return makeQuat(q.w, -q.x, -q.y, -q.z); }
|
||||
inline Quat inv(const Quat &q) { return scale(conj(q), 1.0f/normsq(q)); }
|
||||
Quat mult(const Quat &q, const Quat &p);
|
||||
inline V3d rotate(const V3d &v, const Quat &q) { return mult(mult(q, makeQuat(0.0f, v)), conj(q)).vec(); }
|
||||
Quat cross(const Quat &q, const Quat &p);
|
||||
inline float32 inner(const Quat &q, const Quat &p) { return q.w*p.w - q.x*p.x - q.y*p.y - q.z*p.z; }
|
||||
inline float32 dot(const Quat &q, const Quat &p) { return q.w*p.w + q.x*p.x + q.y*p.y + q.z*p.z; }
|
||||
inline Quat sandwich(const Quat &q, const Quat &v) { return mult(mult(q, v), conj(q)); }
|
||||
inline Quat transform(const Quat &q, const Quat &v) { return scale(sandwich(q, v), 1.0f/normsq(q)); }
|
||||
Quat exp(const Quat &q);
|
||||
Quat log(const Quat &q);
|
||||
Quat lerp(const Quat &q, const Quat &p, float32 r);
|
||||
Quat slerp(const Quat &q, const Quat &p, float32 a);
|
||||
inline V3d rotate(const V3d &v, const Quat &q) { return transform(q, makeQuat(0.0f, v)).vec(); }
|
||||
|
||||
// Dual Quaternion
|
||||
// not a RW type
|
||||
struct DQuat
|
||||
{
|
||||
Quat r, d;
|
||||
};
|
||||
inline DQuat makeDQuat(const Quat &r, const Quat &d) { DQuat q; q.r = r; q.d = d; return q; }
|
||||
inline DQuat makeDQuat(const Quat &r) { DQuat q; q.r = r; q.d = makeQuat(0.0f, 0.0f, 0.0f, 0.0f); return q; }
|
||||
inline DQuat add(const DQuat &q, const DQuat &p) { return makeDQuat(add(q.r,p.r), add(q.d,p.d)); }
|
||||
inline DQuat sub(const DQuat &q, const DQuat &p) { return makeDQuat(sub(q.r,p.r), sub(q.d,p.d)); }
|
||||
inline DQuat negate(const DQuat &q) { return makeDQuat(negate(q.r), negate(q.d)); }
|
||||
inline DQuat scale(const DQuat &q, float32 r) { return makeDQuat(scale(q.r,r), scale(q.d,r)); }
|
||||
|
||||
|
||||
struct RawMatrix
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ if(LIBRW_EXAMPLES)
|
||||
add_subdirectory(camera)
|
||||
add_subdirectory(im2d)
|
||||
add_subdirectory(im3d)
|
||||
add_subdirectory(demoreel)
|
||||
endif()
|
||||
|
||||
if(LIBRW_PLATFORM_PS2)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
add_executable(demoreel WIN32
|
||||
demoreel.h
|
||||
main.cpp
|
||||
proctex.cpp
|
||||
scene_knot.cpp
|
||||
scene_particles.cpp
|
||||
scene_tunnel.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(demoreel
|
||||
PRIVATE
|
||||
librw::skeleton
|
||||
librw::librw
|
||||
)
|
||||
|
||||
librw_platform_target(demoreel)
|
||||
@@ -0,0 +1,62 @@
|
||||
# PS2 build (SCE toolchain). PC builds are generated by premake.
|
||||
# Build librw for ps2 first: premake5 gmake; make -C build librw config=debug_ps2
|
||||
|
||||
CC=ee-gcc
|
||||
CXX=ee-g++
|
||||
|
||||
TARGET=demoreel
|
||||
|
||||
LIBRW := ../..
|
||||
OBJDIR := obj/ps2
|
||||
|
||||
SRC := main.cpp proctex.cpp scene_tunnel.cpp scene_particles.cpp scene_knot.cpp
|
||||
SKELSRC := skeleton.cpp ps2.cpp
|
||||
|
||||
SCELIBDIR := /usr/local/sce/ee/lib
|
||||
|
||||
CFLAGS := -Os -DRW_PS2 -fno-common -fno-exceptions
|
||||
|
||||
LIBS = $(LIBRW)/lib/ps2/Debug/librw.a \
|
||||
$(SCELIBDIR)/libgraph.a \
|
||||
$(SCELIBDIR)/libdma.a \
|
||||
$(SCELIBDIR)/libmc.a \
|
||||
$(SCELIBDIR)/libpc.a \
|
||||
$(SCELIBDIR)/libpad.a \
|
||||
$(SCELIBDIR)/libcdvd.a \
|
||||
$(SCELIBDIR)/libscf.a
|
||||
|
||||
GCCLIB := /usr/local/sce/ee/gcc/lib/gcc-lib/ee/3.2-ee-030926
|
||||
CRT_BEGIN := $(OBJDIR)/crt0.o $(GCCLIB)/crti.o $(GCCLIB)/crtbegin.o
|
||||
CRT_END := $(GCCLIB)/crtend.o $(GCCLIB)/crtn.o
|
||||
|
||||
OBJ := $(addprefix $(OBJDIR)/,$(SRC:.cpp=.o) $(SKELSRC:.cpp=.o))
|
||||
DEP := $(OBJ:.o=.d)
|
||||
|
||||
INC := -I. \
|
||||
-I$(LIBRW) \
|
||||
-I$(LIBRW)/skeleton \
|
||||
-I/usr/local/sce/common/include \
|
||||
-I/usr/local/sce/ee/include
|
||||
|
||||
$(TARGET).elf: $(OBJDIR)/crt0.o $(OBJ)
|
||||
$(CXX) -o $@ $(CRT_BEGIN) $(OBJ) $(LIBS) $(CRT_END) -T $(SCELIBDIR)/app.cmd -L$(SCELIBDIR) -lm -nostartfiles -Wl,--gc-sections
|
||||
|
||||
run: $(TARGET).elf
|
||||
dsedb -r run $(TARGET).elf
|
||||
|
||||
$(OBJDIR)/crt0.o:
|
||||
@mkdir -p $(@D)
|
||||
$(CC) -c -xassembler-with-cpp -o $@ $(SCELIBDIR)/crt0.s
|
||||
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CFLAGS) $(INC) -MMD -c $< -o $@
|
||||
|
||||
$(OBJDIR)/%.o: $(LIBRW)/skeleton/%.cpp
|
||||
@mkdir -p $(@D)
|
||||
$(CXX) $(CFLAGS) $(INC) -MMD -c $< -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJDIR) $(TARGET).elf
|
||||
|
||||
-include $(DEP)
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef DEMOREEL_H
|
||||
#define DEMOREEL_H
|
||||
|
||||
#include <rw.h>
|
||||
#include <skeleton.h>
|
||||
|
||||
// A demo scene. Plain function pointers and static data only;
|
||||
// scene code is meant to stay compilable for PS2 (old gcc, no STL).
|
||||
struct DemoScene
|
||||
{
|
||||
const char *name;
|
||||
void (*init)(void);
|
||||
void (*term)(void);
|
||||
void (*update)(float dt);
|
||||
void (*render)(void);
|
||||
};
|
||||
|
||||
struct SceneGlobals
|
||||
{
|
||||
rw::World *world;
|
||||
rw::Camera *camera;
|
||||
};
|
||||
extern SceneGlobals Scene;
|
||||
extern float DemoTime; // seconds since scene start
|
||||
|
||||
// main.cpp
|
||||
void LookAt(rw::Frame *frame, rw::V3d pos, rw::V3d target);
|
||||
rw::RGBA HSV(float h, float s, float v, rw::uint8 alpha);
|
||||
|
||||
// proctex.cpp
|
||||
rw::Texture *MakeGlowTexture(void);
|
||||
rw::Texture *MakeGridTexture(void);
|
||||
rw::Texture *MakeEnvTexture(void);
|
||||
|
||||
extern DemoScene TunnelScene;
|
||||
extern DemoScene ParticleScene;
|
||||
extern DemoScene KnotScene;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,301 @@
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "demoreel.h"
|
||||
|
||||
rw::EngineOpenParams engineOpenParams;
|
||||
|
||||
rw::RGBA ForegroundColor = { 200, 200, 200, 255 };
|
||||
rw::RGBA BackgroundColor = { 0, 0, 0, 0 };
|
||||
|
||||
SceneGlobals Scene;
|
||||
float DemoTime;
|
||||
|
||||
float TimeDelta;
|
||||
|
||||
static DemoScene *scenes[] = {
|
||||
&TunnelScene,
|
||||
&ParticleScene,
|
||||
&KnotScene,
|
||||
};
|
||||
static int numScenes = sizeof(scenes)/sizeof(scenes[0]);
|
||||
static int curScene = -1;
|
||||
static int nextScene = 0;
|
||||
|
||||
void
|
||||
LookAt(rw::Frame *frame, rw::V3d pos, rw::V3d target)
|
||||
{
|
||||
static rw::V3d worldup = { 0.0f, 0.0f, 1.0f };
|
||||
rw::Matrix m;
|
||||
rw::V3d at, right, up;
|
||||
|
||||
at = rw::normalize(rw::sub(target, pos));
|
||||
right = rw::cross(worldup, at);
|
||||
if(rw::length(right) < 0.001f)
|
||||
right.x = 1.0f, right.y = right.z = 0.0f;
|
||||
right = rw::normalize(right);
|
||||
up = rw::cross(at, right);
|
||||
|
||||
m.setIdentity();
|
||||
m.right = right;
|
||||
m.up = up;
|
||||
m.at = at;
|
||||
m.pos = pos;
|
||||
m.optimize();
|
||||
frame->transform(&m, rw::COMBINEREPLACE);
|
||||
}
|
||||
|
||||
rw::RGBA
|
||||
HSV(float h, float s, float v, rw::uint8 alpha)
|
||||
{
|
||||
rw::RGBA col;
|
||||
float r, g, b;
|
||||
float f, p, q, t;
|
||||
int i;
|
||||
|
||||
h = h - floorf(h);
|
||||
h *= 6.0f;
|
||||
i = (int)h;
|
||||
f = h - i;
|
||||
p = v*(1.0f - s);
|
||||
q = v*(1.0f - s*f);
|
||||
t = v*(1.0f - s*(1.0f - f));
|
||||
switch(i){
|
||||
default:
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
col.red = (rw::uint8)(r*255.0f);
|
||||
col.green = (rw::uint8)(g*255.0f);
|
||||
col.blue = (rw::uint8)(b*255.0f);
|
||||
col.alpha = alpha;
|
||||
return col;
|
||||
}
|
||||
|
||||
static void
|
||||
SwitchScene(int n)
|
||||
{
|
||||
while(n < 0) n += numScenes;
|
||||
n %= numScenes;
|
||||
if(n == curScene)
|
||||
return;
|
||||
if(curScene >= 0)
|
||||
scenes[curScene]->term();
|
||||
curScene = n;
|
||||
DemoTime = 0.0f;
|
||||
scenes[curScene]->init();
|
||||
}
|
||||
|
||||
rw::World*
|
||||
CreateWorld(void)
|
||||
{
|
||||
rw::BBox bb;
|
||||
bb.inf.x = bb.inf.y = bb.inf.z = -1000.0f;
|
||||
bb.sup.x = bb.sup.y = bb.sup.z = 1000.0f;
|
||||
return rw::World::create(&bb);
|
||||
}
|
||||
|
||||
rw::Camera*
|
||||
CreateCamera(rw::World *world)
|
||||
{
|
||||
rw::Camera *camera;
|
||||
camera = sk::CameraCreate(sk::globals.width, sk::globals.height, 1);
|
||||
assert(camera);
|
||||
camera->setNearPlane(0.1f);
|
||||
camera->setFarPlane(300.0f);
|
||||
camera->setFOV(70.0f, (float)sk::globals.width/sk::globals.height);
|
||||
world->addCamera(camera);
|
||||
return camera;
|
||||
}
|
||||
|
||||
void
|
||||
Initialize(void)
|
||||
{
|
||||
sk::globals.windowtitle = "librw demo reel";
|
||||
sk::globals.width = 1280;
|
||||
sk::globals.height = 800;
|
||||
sk::globals.quit = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Initialize3D(void)
|
||||
{
|
||||
if(!sk::InitRW())
|
||||
return false;
|
||||
|
||||
Scene.world = CreateWorld();
|
||||
Scene.camera = CreateCamera(Scene.world);
|
||||
|
||||
#ifndef RW_PS2
|
||||
ImGui_ImplRW_Init();
|
||||
ImGui::StyleColorsClassic();
|
||||
#endif
|
||||
|
||||
SwitchScene(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Terminate3D(void)
|
||||
{
|
||||
if(curScene >= 0){
|
||||
scenes[curScene]->term();
|
||||
curScene = -1;
|
||||
}
|
||||
|
||||
if(Scene.camera){
|
||||
Scene.world->removeCamera(Scene.camera);
|
||||
Scene.camera->destroy();
|
||||
Scene.camera = nil;
|
||||
}
|
||||
if(Scene.world){
|
||||
Scene.world->destroy();
|
||||
Scene.world = nil;
|
||||
}
|
||||
|
||||
sk::TerminateRW();
|
||||
}
|
||||
|
||||
bool
|
||||
attachPlugins(void)
|
||||
{
|
||||
rw::ps2::registerPDSPlugin(40);
|
||||
rw::ps2::registerPluginPDSPipes();
|
||||
|
||||
rw::registerMeshPlugin();
|
||||
rw::registerNativeDataPlugin();
|
||||
rw::registerAtomicRightsPlugin();
|
||||
rw::registerMaterialRightsPlugin();
|
||||
rw::xbox::registerVertexFormatPlugin();
|
||||
rw::registerSkinPlugin();
|
||||
rw::registerUserDataPlugin();
|
||||
rw::registerHAnimPlugin();
|
||||
rw::registerMatFXPlugin();
|
||||
rw::registerUVAnimPlugin();
|
||||
rw::ps2::registerADCPlugin();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef RW_PS2
|
||||
void
|
||||
Gui(void)
|
||||
{
|
||||
static bool showWindow = true;
|
||||
int i;
|
||||
|
||||
ImGui::Begin("Demo reel", &showWindow);
|
||||
for(i = 0; i < numScenes; i++)
|
||||
if(ImGui::RadioButton(scenes[i]->name, curScene == i))
|
||||
nextScene = i;
|
||||
ImGui::NewLine();
|
||||
ImGui::Text("%.1f fps", 1.0f/TimeDelta);
|
||||
ImGui::End();
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Render(void)
|
||||
{
|
||||
Scene.camera->clear(&BackgroundColor, rw::Camera::CLEARIMAGE|rw::Camera::CLEARZ);
|
||||
|
||||
Scene.camera->beginUpdate();
|
||||
|
||||
#ifndef RW_PS2
|
||||
ImGui_ImplRW_NewFrame(TimeDelta);
|
||||
#endif
|
||||
|
||||
scenes[curScene]->render();
|
||||
|
||||
#ifndef RW_PS2
|
||||
Gui();
|
||||
ImGui::EndFrame();
|
||||
ImGui::Render();
|
||||
ImGui_ImplRW_RenderDrawLists(ImGui::GetDrawData());
|
||||
#endif
|
||||
|
||||
Scene.camera->endUpdate();
|
||||
|
||||
Scene.camera->showRaster(0);
|
||||
}
|
||||
|
||||
void
|
||||
Idle(float timeDelta)
|
||||
{
|
||||
TimeDelta = timeDelta;
|
||||
if(TimeDelta <= 0.0f) TimeDelta = 1.0f/60.0f;
|
||||
if(TimeDelta > 0.1f) TimeDelta = 0.1f;
|
||||
|
||||
SwitchScene(nextScene);
|
||||
nextScene = curScene;
|
||||
|
||||
DemoTime += TimeDelta;
|
||||
scenes[curScene]->update(TimeDelta);
|
||||
|
||||
Render();
|
||||
}
|
||||
|
||||
void
|
||||
KeyDown(int key)
|
||||
{
|
||||
switch(key){
|
||||
case sk::KEY_ESC:
|
||||
sk::globals.quit = 1;
|
||||
break;
|
||||
case sk::KEY_LEFT:
|
||||
nextScene = curScene-1;
|
||||
break;
|
||||
case sk::KEY_RIGHT:
|
||||
case ' ':
|
||||
nextScene = curScene+1;
|
||||
break;
|
||||
default:
|
||||
if(key >= '1' && key < '1'+numScenes)
|
||||
nextScene = key-'1';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sk::EventStatus
|
||||
AppEventHandler(sk::Event e, void *param)
|
||||
{
|
||||
using namespace sk;
|
||||
Rect *r;
|
||||
|
||||
#ifndef RW_PS2
|
||||
ImGuiEventHandler(e, param);
|
||||
#endif
|
||||
|
||||
switch(e){
|
||||
case INITIALIZE:
|
||||
Initialize();
|
||||
return EVENTPROCESSED;
|
||||
case RWINITIALIZE:
|
||||
return Initialize3D() ? EVENTPROCESSED : EVENTERROR;
|
||||
case RWTERMINATE:
|
||||
Terminate3D();
|
||||
return EVENTPROCESSED;
|
||||
case PLUGINATTACH:
|
||||
return attachPlugins() ? EVENTPROCESSED : EVENTERROR;
|
||||
case KEYDOWN:
|
||||
KeyDown(*(int*)param);
|
||||
return EVENTPROCESSED;
|
||||
case RESIZE:
|
||||
r = (Rect*)param;
|
||||
if(r->w == 0) r->w = 1;
|
||||
if(r->h == 0) r->h = 1;
|
||||
sk::globals.width = r->w;
|
||||
sk::globals.height = r->h;
|
||||
if(Scene.camera)
|
||||
sk::CameraSize(Scene.camera, r, 0.5f, 4.0f/3.0f);
|
||||
break;
|
||||
case IDLE:
|
||||
Idle(*(float*)param);
|
||||
return EVENTPROCESSED;
|
||||
}
|
||||
return sk::EVENTNOTPROCESSED;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "demoreel.h"
|
||||
|
||||
// Procedural textures so the demos need no asset files at all.
|
||||
|
||||
using namespace rw;
|
||||
|
||||
static Texture*
|
||||
imageToTexture(Image *img)
|
||||
{
|
||||
Raster *ras = Raster::createFromImage(img);
|
||||
img->destroy();
|
||||
if(ras == nil)
|
||||
return nil;
|
||||
Texture *tex = Texture::create(ras);
|
||||
tex->setFilter(Texture::LINEAR);
|
||||
tex->setAddressU(Texture::WRAP);
|
||||
tex->setAddressV(Texture::WRAP);
|
||||
return tex;
|
||||
}
|
||||
|
||||
// soft radial blob for additive particles
|
||||
Texture*
|
||||
MakeGlowTexture(void)
|
||||
{
|
||||
const int SZ = 64;
|
||||
Image *img = Image::create(SZ, SZ, 32);
|
||||
img->allocate();
|
||||
|
||||
int x, y;
|
||||
for(y = 0; y < SZ; y++){
|
||||
uint8 *line = img->pixels + y*img->stride;
|
||||
for(x = 0; x < SZ; x++){
|
||||
float dx = (x + 0.5f - SZ/2) / (SZ/2);
|
||||
float dy = (y + 0.5f - SZ/2) / (SZ/2);
|
||||
float r = sqrtf(dx*dx + dy*dy);
|
||||
float v = 1.0f - r;
|
||||
if(v < 0.0f) v = 0.0f;
|
||||
v = v*v*(3.0f - 2.0f*v); // smoothstep
|
||||
v = v*v; // sharpen the core
|
||||
uint8 c = (uint8)(v*255.0f);
|
||||
line[x*4+0] = c;
|
||||
line[x*4+1] = c;
|
||||
line[x*4+2] = c;
|
||||
line[x*4+3] = c;
|
||||
}
|
||||
}
|
||||
return imageToTexture(img);
|
||||
}
|
||||
|
||||
// glowing neon grid on dark ground
|
||||
Texture*
|
||||
MakeGridTexture(void)
|
||||
{
|
||||
const int SZ = 128;
|
||||
const int CELL = 32;
|
||||
Image *img = Image::create(SZ, SZ, 32);
|
||||
img->allocate();
|
||||
|
||||
int x, y;
|
||||
for(y = 0; y < SZ; y++){
|
||||
uint8 *line = img->pixels + y*img->stride;
|
||||
for(x = 0; x < SZ; x++){
|
||||
int mx = x % CELL; if(mx > CELL/2) mx = CELL-mx;
|
||||
int my = y % CELL; if(my > CELL/2) my = CELL-my;
|
||||
int d = mx < my ? mx : my;
|
||||
float v = 1.0f - d/6.0f;
|
||||
if(v < 0.0f) v = 0.0f;
|
||||
v = v*v;
|
||||
// dark blue ground, cyan-white lines
|
||||
float r = 0.02f + v*0.75f;
|
||||
float g = 0.03f + v*0.95f;
|
||||
float b = 0.10f + v*0.90f;
|
||||
line[x*4+0] = (uint8)(r*255.0f);
|
||||
line[x*4+1] = (uint8)(g*255.0f);
|
||||
line[x*4+2] = (uint8)(b*255.0f);
|
||||
line[x*4+3] = 255;
|
||||
}
|
||||
}
|
||||
return imageToTexture(img);
|
||||
}
|
||||
|
||||
// fake sky-ground gradient with highlight streaks, for env mapping
|
||||
Texture*
|
||||
MakeEnvTexture(void)
|
||||
{
|
||||
const int SZ = 128;
|
||||
Image *img = Image::create(SZ, SZ, 32);
|
||||
img->allocate();
|
||||
|
||||
int x, y;
|
||||
for(y = 0; y < SZ; y++){
|
||||
uint8 *line = img->pixels + y*img->stride;
|
||||
float fy = (float)y/SZ;
|
||||
for(x = 0; x < SZ; x++){
|
||||
float fx = (float)x/SZ;
|
||||
float r, g, b;
|
||||
if(fy < 0.5f){
|
||||
// sky: bright at horizon
|
||||
float t = fy*2.0f;
|
||||
r = 0.05f + t*0.55f;
|
||||
g = 0.15f + t*0.65f;
|
||||
b = 0.35f + t*0.65f;
|
||||
}else{
|
||||
// ground: dark, fading down
|
||||
float t = (fy-0.5f)*2.0f;
|
||||
r = 0.45f - t*0.40f;
|
||||
g = 0.35f - t*0.32f;
|
||||
b = 0.30f - t*0.28f;
|
||||
}
|
||||
// horizon band
|
||||
float h = fabsf(fy - 0.5f);
|
||||
float band = 1.0f - h*8.0f;
|
||||
if(band > 0.0f){
|
||||
band = band*band;
|
||||
r += band*0.5f;
|
||||
g += band*0.5f;
|
||||
b += band*0.4f;
|
||||
}
|
||||
// vertical highlight streaks in the sky
|
||||
float streak = sinf(fx*3.14159f*6.0f);
|
||||
streak = streak*streak*streak*streak;
|
||||
if(fy < 0.5f)
|
||||
r += streak*0.15f, g += streak*0.15f, b += streak*0.1f;
|
||||
|
||||
if(r > 1.0f) r = 1.0f;
|
||||
if(g > 1.0f) g = 1.0f;
|
||||
if(b > 1.0f) b = 1.0f;
|
||||
line[x*4+0] = (uint8)(r*255.0f);
|
||||
line[x*4+1] = (uint8)(g*255.0f);
|
||||
line[x*4+2] = (uint8)(b*255.0f);
|
||||
line[x*4+3] = 255;
|
||||
}
|
||||
}
|
||||
return imageToTexture(img);
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "demoreel.h"
|
||||
|
||||
// Retained mode: a procedural torus knot with env-mapped chrome,
|
||||
// lit by two colored directional lights. Exercises Geometry
|
||||
// creation, materials, MatFX and the world/light path.
|
||||
|
||||
using namespace rw;
|
||||
|
||||
#define KNOT_P 2
|
||||
#define KNOT_Q 3
|
||||
|
||||
#define SEGS 160
|
||||
#define SIDES 12
|
||||
#define NUMVERTS ((SEGS+1)*(SIDES+1))
|
||||
#define NUMTRIS (SEGS*SIDES*2)
|
||||
|
||||
static Atomic *knotAtomic;
|
||||
static Frame *knotFrame;
|
||||
static Light *ambient;
|
||||
static Light *keyLight;
|
||||
static Light *fillLight;
|
||||
static Texture *envTex;
|
||||
static Texture *gridTex;
|
||||
|
||||
static V3d
|
||||
knotCenter(float t)
|
||||
{
|
||||
V3d p;
|
||||
float r = 6.0f + 2.5f*cosf(KNOT_Q*t);
|
||||
p.x = r*cosf(KNOT_P*t);
|
||||
p.y = r*sinf(KNOT_P*t);
|
||||
p.z = 2.5f*sinf(KNOT_Q*t);
|
||||
return p;
|
||||
}
|
||||
|
||||
static Geometry*
|
||||
CreateKnotGeometry(void)
|
||||
{
|
||||
Geometry *geo = Geometry::create(NUMVERTS, NUMTRIS,
|
||||
Geometry::POSITIONS | Geometry::NORMALS |
|
||||
Geometry::LIGHT | Geometry::TEXTURED);
|
||||
assert(geo);
|
||||
|
||||
MorphTarget *mt = &geo->morphTargets[0];
|
||||
V3d *verts = mt->vertices;
|
||||
V3d *norms = mt->normals;
|
||||
TexCoords *uv = geo->texCoords[0];
|
||||
|
||||
float tuberad = 1.1f;
|
||||
int i, j, v;
|
||||
|
||||
v = 0;
|
||||
for(i = 0; i <= SEGS; i++){
|
||||
float t = (float)i/SEGS*2.0f*3.14159265f;
|
||||
V3d c = knotCenter(t);
|
||||
V3d tan = normalize(sub(knotCenter(t+0.01f), knotCenter(t-0.01f)));
|
||||
static V3d worldup = { 0.0f, 0.0f, 1.0f };
|
||||
V3d n = normalize(cross(worldup, tan));
|
||||
V3d b = cross(tan, n);
|
||||
|
||||
for(j = 0; j <= SIDES; j++){
|
||||
float a = (float)j/SIDES*2.0f*3.14159265f;
|
||||
V3d ring = add(scale(n, cosf(a)), scale(b, sinf(a)));
|
||||
verts[v] = add(c, scale(ring, tuberad));
|
||||
norms[v] = ring;
|
||||
uv[v].u = (float)i/SEGS*24.0f;
|
||||
uv[v].v = (float)j/SIDES;
|
||||
v++;
|
||||
}
|
||||
}
|
||||
|
||||
Triangle *tri = geo->triangles;
|
||||
for(i = 0; i < SEGS; i++)
|
||||
for(j = 0; j < SIDES; j++){
|
||||
int r0 = i*(SIDES+1) + j;
|
||||
int r1 = (i+1)*(SIDES+1) + j;
|
||||
tri->v[0] = r0; tri->v[1] = r0+1; tri->v[2] = r1;
|
||||
tri->matId = 0;
|
||||
tri++;
|
||||
tri->v[0] = r0+1; tri->v[1] = r1+1; tri->v[2] = r1;
|
||||
tri->matId = 0;
|
||||
tri++;
|
||||
}
|
||||
|
||||
Material *mat = Material::create();
|
||||
gridTex = MakeGridTexture();
|
||||
if(gridTex)
|
||||
mat->setTexture(gridTex);
|
||||
envTex = MakeEnvTexture();
|
||||
MatFX::setEffects(mat, MatFX::ENVMAP);
|
||||
MatFX *mfx = MatFX::get(mat);
|
||||
if(envTex)
|
||||
mfx->setEnvTexture(envTex);
|
||||
mfx->setEnvFrame(Scene.camera->getFrame());
|
||||
mfx->setEnvCoefficient(0.6f);
|
||||
geo->matList.appendMaterial(mat);
|
||||
mat->destroy(); // list holds a ref now
|
||||
|
||||
geo->calculateBoundingSphere();
|
||||
// strips are the well-trodden path on PS2 (and a test for the tristripper)
|
||||
geo->flags |= Geometry::TRISTRIP;
|
||||
geo->buildMeshes();
|
||||
return geo;
|
||||
}
|
||||
|
||||
static Light*
|
||||
MakeDirLight(float r, float g, float b, float yaw, float pitch)
|
||||
{
|
||||
static V3d Xaxis = { 1.0f, 0.0f, 0.0f };
|
||||
static V3d Zaxis = { 0.0f, 0.0f, 1.0f };
|
||||
Light *light = Light::create(Light::DIRECTIONAL);
|
||||
light->setColor(r, g, b);
|
||||
Frame *f = Frame::create();
|
||||
f->rotate(&Xaxis, pitch, COMBINEREPLACE);
|
||||
f->rotate(&Zaxis, yaw, COMBINEPOSTCONCAT);
|
||||
light->setFrame(f);
|
||||
Scene.world->addLight(light);
|
||||
return light;
|
||||
}
|
||||
|
||||
static void
|
||||
KnotInit(void)
|
||||
{
|
||||
Geometry *geo = CreateKnotGeometry();
|
||||
|
||||
knotFrame = Frame::create();
|
||||
knotAtomic = Atomic::create();
|
||||
knotAtomic->setGeometry(geo, 0);
|
||||
geo->destroy(); // atomic holds a ref now
|
||||
knotAtomic->setFrame(knotFrame);
|
||||
MatFX::enableEffects(knotAtomic);
|
||||
Scene.world->addAtomic(knotAtomic);
|
||||
|
||||
ambient = Light::create(Light::AMBIENT);
|
||||
ambient->setColor(0.15f, 0.15f, 0.2f);
|
||||
Scene.world->addLight(ambient);
|
||||
keyLight = MakeDirLight(1.0f, 0.85f, 0.6f, 30.0f, 120.0f);
|
||||
fillLight = MakeDirLight(0.3f, 0.4f, 0.9f, 200.0f, 60.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
KnotTerm(void)
|
||||
{
|
||||
if(knotAtomic){
|
||||
Scene.world->removeAtomic(knotAtomic);
|
||||
knotAtomic->destroy();
|
||||
knotAtomic = nil;
|
||||
}
|
||||
if(knotFrame){
|
||||
knotFrame->destroy();
|
||||
knotFrame = nil;
|
||||
}
|
||||
if(ambient){
|
||||
Scene.world->removeLight(ambient);
|
||||
ambient->destroy();
|
||||
ambient = nil;
|
||||
}
|
||||
if(keyLight){
|
||||
Scene.world->removeLight(keyLight);
|
||||
Frame *f = keyLight->getFrame();
|
||||
keyLight->setFrame(nil);
|
||||
f->destroy();
|
||||
keyLight->destroy();
|
||||
keyLight = nil;
|
||||
}
|
||||
if(fillLight){
|
||||
Scene.world->removeLight(fillLight);
|
||||
Frame *f = fillLight->getFrame();
|
||||
fillLight->setFrame(nil);
|
||||
f->destroy();
|
||||
fillLight->destroy();
|
||||
fillLight = nil;
|
||||
}
|
||||
if(envTex){
|
||||
envTex->destroy();
|
||||
envTex = nil;
|
||||
}
|
||||
if(gridTex){
|
||||
gridTex->destroy();
|
||||
gridTex = nil;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
KnotUpdate(float dt)
|
||||
{
|
||||
static V3d Xaxis = { 1.0f, 0.0f, 0.0f };
|
||||
static V3d Zaxis = { 0.0f, 0.0f, 1.0f };
|
||||
|
||||
knotFrame->rotate(&Zaxis, dt*20.0f, COMBINEPOSTCONCAT);
|
||||
knotFrame->rotate(&Xaxis, dt*8.0f, COMBINEPRECONCAT);
|
||||
|
||||
float ca = DemoTime*0.1f;
|
||||
V3d campos;
|
||||
campos.x = 24.0f*cosf(ca);
|
||||
campos.y = 24.0f*sinf(ca);
|
||||
campos.z = 8.0f*sinf(DemoTime*0.23f);
|
||||
V3d origin = { 0.0f, 0.0f, 0.0f };
|
||||
LookAt(Scene.camera->getFrame(), campos, origin);
|
||||
}
|
||||
|
||||
static void
|
||||
KnotRender(void)
|
||||
{
|
||||
SetRenderState(ZTESTENABLE, 1);
|
||||
SetRenderState(ZWRITEENABLE, 1);
|
||||
SetRenderState(CULLMODE, CULLBACK);
|
||||
|
||||
knotAtomic->render();
|
||||
}
|
||||
|
||||
DemoScene KnotScene = {
|
||||
"Torus knot",
|
||||
KnotInit,
|
||||
KnotTerm,
|
||||
KnotUpdate,
|
||||
KnotRender
|
||||
};
|
||||
@@ -0,0 +1,165 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "demoreel.h"
|
||||
|
||||
// Additive-blended particle vortex, camera-facing quads via im3d.
|
||||
// The kind of thing the GS fillrate was made for.
|
||||
|
||||
using namespace rw;
|
||||
|
||||
#ifdef RW_PS2
|
||||
#define NUMPARTS 600
|
||||
#else
|
||||
#define NUMPARTS 1200
|
||||
#endif
|
||||
|
||||
struct Particle
|
||||
{
|
||||
float angle;
|
||||
float radius;
|
||||
float height;
|
||||
float size;
|
||||
float phase;
|
||||
};
|
||||
|
||||
static Particle parts[NUMPARTS];
|
||||
static RWDEVICE::Im3DVertex partVerts[NUMPARTS*4];
|
||||
static uint16 partIndices[NUMPARTS*6];
|
||||
static Texture *glowTex;
|
||||
static Matrix identMat;
|
||||
|
||||
// cheap deterministic pseudo-random, no libc rand()
|
||||
static float
|
||||
frand(int n)
|
||||
{
|
||||
n = (n<<13) ^ n;
|
||||
n = n*(n*n*15731 + 789221) + 1376312589;
|
||||
return ((n & 0x7fffffff) / (float)0x7fffffff);
|
||||
}
|
||||
|
||||
static void
|
||||
ParticleInit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
glowTex = MakeGlowTexture();
|
||||
identMat.setIdentity();
|
||||
|
||||
for(i = 0; i < NUMPARTS; i++){
|
||||
Particle *p = &parts[i];
|
||||
float u = (float)i/NUMPARTS;
|
||||
p->radius = 4.0f + 30.0f*powf(u, 0.7f);
|
||||
p->angle = i*2.3999632f + frand(i)*0.6f; // golden angle spiral
|
||||
p->height = (frand(i*3+1) - 0.5f)*10.0f*expf(-p->radius/18.0f);
|
||||
p->size = 0.5f + frand(i*7+2)*1.1f;
|
||||
p->phase = frand(i*13+3)*6.28f;
|
||||
}
|
||||
|
||||
for(i = 0; i < NUMPARTS; i++){
|
||||
partIndices[i*6+0] = i*4+0;
|
||||
partIndices[i*6+1] = i*4+1;
|
||||
partIndices[i*6+2] = i*4+2;
|
||||
partIndices[i*6+3] = i*4+0;
|
||||
partIndices[i*6+4] = i*4+2;
|
||||
partIndices[i*6+5] = i*4+3;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ParticleTerm(void)
|
||||
{
|
||||
if(glowTex){
|
||||
glowTex->destroy();
|
||||
glowTex = nil;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ParticleUpdate(float dt)
|
||||
{
|
||||
int i;
|
||||
|
||||
// differential rotation: inner particles spin faster
|
||||
for(i = 0; i < NUMPARTS; i++){
|
||||
Particle *p = &parts[i];
|
||||
p->angle += dt*16.0f/(p->radius + 4.0f);
|
||||
}
|
||||
|
||||
// slow orbiting camera
|
||||
float ca = DemoTime*0.12f;
|
||||
V3d campos;
|
||||
campos.x = 55.0f*cosf(ca);
|
||||
campos.y = 55.0f*sinf(ca);
|
||||
campos.z = 14.0f + 10.0f*sinf(DemoTime*0.2f);
|
||||
V3d origin = { 0.0f, 0.0f, 0.0f };
|
||||
LookAt(Scene.camera->getFrame(), campos, origin);
|
||||
|
||||
// billboard the quads using the camera axes
|
||||
Matrix *cm = Scene.camera->getFrame()->getLTM();
|
||||
V3d right = cm->right;
|
||||
V3d up = cm->up;
|
||||
|
||||
for(i = 0; i < NUMPARTS; i++){
|
||||
Particle *p = &parts[i];
|
||||
V3d pos;
|
||||
pos.x = p->radius*cosf(p->angle);
|
||||
pos.y = p->radius*sinf(p->angle);
|
||||
pos.z = p->height + 0.8f*sinf(DemoTime*2.0f + p->phase);
|
||||
|
||||
float tw = 0.7f + 0.3f*sinf(DemoTime*5.0f + p->phase);
|
||||
float sz = p->size*tw;
|
||||
RGBA col = HSV(DemoTime*0.02f + p->radius*0.012f, 0.8f, tw, 255);
|
||||
|
||||
RWDEVICE::Im3DVertex *v = &partVerts[i*4];
|
||||
V3d r = scale(right, sz);
|
||||
V3d u = scale(up, sz);
|
||||
V3d pu = add(pos, u);
|
||||
V3d pd = sub(pos, u);
|
||||
V3d c;
|
||||
|
||||
c = sub(pu, r);
|
||||
v[0].setX(c.x); v[0].setY(c.y); v[0].setZ(c.z);
|
||||
v[0].setU(0.0f); v[0].setV(0.0f);
|
||||
c = add(pu, r);
|
||||
v[1].setX(c.x); v[1].setY(c.y); v[1].setZ(c.z);
|
||||
v[1].setU(1.0f); v[1].setV(0.0f);
|
||||
c = add(pd, r);
|
||||
v[2].setX(c.x); v[2].setY(c.y); v[2].setZ(c.z);
|
||||
v[2].setU(1.0f); v[2].setV(1.0f);
|
||||
c = sub(pd, r);
|
||||
v[3].setX(c.x); v[3].setY(c.y); v[3].setZ(c.z);
|
||||
v[3].setU(0.0f); v[3].setV(1.0f);
|
||||
|
||||
int j;
|
||||
for(j = 0; j < 4; j++)
|
||||
v[j].setColor(col.red, col.green, col.blue, col.alpha);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ParticleRender(void)
|
||||
{
|
||||
SetRenderState(ZTESTENABLE, 1);
|
||||
SetRenderState(ZWRITEENABLE, 0);
|
||||
SetRenderState(SRCBLEND, BLENDONE);
|
||||
SetRenderState(DESTBLEND, BLENDONE);
|
||||
SetRenderState(CULLMODE, CULLNONE);
|
||||
SetRenderState(TEXTUREFILTER, Texture::LINEAR);
|
||||
SetRenderStatePtr(TEXTURERASTER, glowTex ? glowTex->raster : nil);
|
||||
|
||||
im3d::Transform(partVerts, NUMPARTS*4, &identMat, im3d::VERTEXUV);
|
||||
im3d::RenderIndexedPrimitive(PRIMTYPETRILIST, partIndices, NUMPARTS*6);
|
||||
im3d::End();
|
||||
|
||||
SetRenderState(ZWRITEENABLE, 1);
|
||||
SetRenderState(SRCBLEND, BLENDSRCALPHA);
|
||||
SetRenderState(DESTBLEND, BLENDINVSRCALPHA);
|
||||
}
|
||||
|
||||
DemoScene ParticleScene = {
|
||||
"Particle vortex",
|
||||
ParticleInit,
|
||||
ParticleTerm,
|
||||
ParticleUpdate,
|
||||
ParticleRender
|
||||
};
|
||||
@@ -0,0 +1,155 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "demoreel.h"
|
||||
|
||||
// Classic endless tunnel: fly along a wobbling closed loop,
|
||||
// vertices regenerated on the CPU every frame, im3d rendering.
|
||||
|
||||
using namespace rw;
|
||||
|
||||
#define SIDES 16
|
||||
#define RINGS 48
|
||||
#define NUMVERTS ((SIDES+1)*(RINGS+1))
|
||||
#define NUMINDICES (SIDES*RINGS*6)
|
||||
|
||||
#define LOOPRADIUS 60.0f
|
||||
|
||||
static RWDEVICE::Im3DVertex tunnelVerts[NUMVERTS];
|
||||
static uint16 tunnelIndices[NUMINDICES];
|
||||
static Texture *gridTex;
|
||||
static Matrix identMat;
|
||||
static float pathPos;
|
||||
|
||||
// closed loop in space with some vertical wobble
|
||||
static V3d
|
||||
tunnelPath(float s)
|
||||
{
|
||||
V3d p;
|
||||
p.x = LOOPRADIUS*cosf(s) + 8.0f*cosf(3.0f*s);
|
||||
p.y = LOOPRADIUS*sinf(s) + 8.0f*sinf(2.0f*s);
|
||||
p.z = 14.0f*sinf(2.0f*s) + 5.0f*sinf(5.0f*s);
|
||||
return p;
|
||||
}
|
||||
|
||||
static float
|
||||
tunnelRadius(float s)
|
||||
{
|
||||
return 6.0f + 1.5f*sinf(5.0f*s + DemoTime*2.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
pathFrame(float s, V3d *pos, V3d *t, V3d *n, V3d *b)
|
||||
{
|
||||
static V3d worldup = { 0.0f, 0.0f, 1.0f };
|
||||
*pos = tunnelPath(s);
|
||||
*t = normalize(sub(tunnelPath(s+0.01f), *pos));
|
||||
*n = normalize(cross(worldup, *t));
|
||||
*b = cross(*t, *n);
|
||||
}
|
||||
|
||||
static void
|
||||
TunnelInit(void)
|
||||
{
|
||||
int i, j, v;
|
||||
|
||||
gridTex = MakeGridTexture();
|
||||
identMat.setIdentity();
|
||||
pathPos = 0.0f;
|
||||
|
||||
v = 0;
|
||||
for(i = 0; i < RINGS; i++)
|
||||
for(j = 0; j < SIDES; j++){
|
||||
int r0 = i*(SIDES+1) + j;
|
||||
int r1 = (i+1)*(SIDES+1) + j;
|
||||
tunnelIndices[v++] = r0;
|
||||
tunnelIndices[v++] = r1;
|
||||
tunnelIndices[v++] = r0+1;
|
||||
tunnelIndices[v++] = r0+1;
|
||||
tunnelIndices[v++] = r1;
|
||||
tunnelIndices[v++] = r1+1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TunnelTerm(void)
|
||||
{
|
||||
if(gridTex){
|
||||
gridTex->destroy();
|
||||
gridTex = nil;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TunnelUpdate(float dt)
|
||||
{
|
||||
pathPos += dt*0.30f;
|
||||
|
||||
// camera rides the tunnel, slightly off center
|
||||
V3d pos, t, n, b;
|
||||
pathFrame(pathPos, &pos, &t, &n, &b);
|
||||
V3d target = tunnelPath(pathPos + 0.15f);
|
||||
pos = add(pos, scale(b, -1.5f*sinf(DemoTime*0.7f)));
|
||||
pos = add(pos, scale(n, 1.5f*cosf(DemoTime*0.5f)));
|
||||
LookAt(Scene.camera->getFrame(), pos, target);
|
||||
|
||||
// rebuild the tube
|
||||
float ds = 0.028f;
|
||||
float hue = DemoTime*0.03f;
|
||||
// V texcoords must stay small: the GS wraps texel
|
||||
// coordinates beyond ~1024, so shift out the integer part
|
||||
float vscale = 4.0f;
|
||||
float vbase = floorf(pathPos*vscale);
|
||||
int i, j, v;
|
||||
|
||||
v = 0;
|
||||
for(i = 0; i <= RINGS; i++){
|
||||
float s = pathPos - ds + i*ds;
|
||||
V3d c, tt, nn, bb;
|
||||
pathFrame(s, &c, &tt, &nn, &bb);
|
||||
float rad = tunnelRadius(s);
|
||||
|
||||
// brightness: fade out towards the far end, pulses running along
|
||||
float fade = 1.0f - (float)i/RINGS;
|
||||
fade = fade*fade;
|
||||
float pulse = 0.55f + 0.45f*sinf(s*18.0f - DemoTime*6.0f);
|
||||
float bright = fade*(0.35f + 0.65f*pulse);
|
||||
RGBA col = HSV(hue + s*0.02f, 0.55f, bright, 255);
|
||||
|
||||
float twist = DemoTime*0.4f;
|
||||
for(j = 0; j <= SIDES; j++){
|
||||
float a = (float)j/SIDES*2.0f*3.14159265f + twist;
|
||||
V3d p = add(c, add(scale(nn, rad*cosf(a)), scale(bb, rad*sinf(a))));
|
||||
RWDEVICE::Im3DVertex *vert = &tunnelVerts[v++];
|
||||
vert->setX(p.x);
|
||||
vert->setY(p.y);
|
||||
vert->setZ(p.z);
|
||||
vert->setU((float)j/SIDES*4.0f);
|
||||
vert->setV(s*vscale - vbase);
|
||||
vert->setColor(col.red, col.green, col.blue, col.alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
TunnelRender(void)
|
||||
{
|
||||
SetRenderState(ZTESTENABLE, 1);
|
||||
SetRenderState(ZWRITEENABLE, 1);
|
||||
SetRenderState(SRCBLEND, BLENDSRCALPHA);
|
||||
SetRenderState(DESTBLEND, BLENDINVSRCALPHA);
|
||||
SetRenderState(CULLMODE, CULLNONE);
|
||||
SetRenderState(TEXTUREFILTER, Texture::LINEAR);
|
||||
SetRenderStatePtr(TEXTURERASTER, gridTex ? gridTex->raster : nil);
|
||||
|
||||
im3d::Transform(tunnelVerts, NUMVERTS, &identMat, im3d::VERTEXUV|im3d::ALLOPAQUE);
|
||||
im3d::RenderIndexedPrimitive(PRIMTYPETRILIST, tunnelIndices, NUMINDICES);
|
||||
im3d::End();
|
||||
}
|
||||
|
||||
DemoScene TunnelScene = {
|
||||
"Tunnel",
|
||||
TunnelInit,
|
||||
TunnelTerm,
|
||||
TunnelUpdate,
|
||||
TunnelRender
|
||||
};
|
||||
Reference in New Issue
Block a user