From 177d6faec47cd5ce72786531d0a019255dbd71f5 Mon Sep 17 00:00:00 2001 From: aap Date: Wed, 23 Jun 2021 22:28:07 +0200 Subject: [PATCH] first commit --- makecom/sky/cwppsky | 241 ++++++++++++ makecom/sky/cwsky | 262 +++++++++++++ makecom/sky/sky295 | 326 ++++++++++++++++ makecom/sky/sky2953 | 323 ++++++++++++++++ makecom/sky/skygcc | 276 ++++++++++++++ makecom/sky/skygpp | 8 + makecom/sky/skyprodg | 237 ++++++++++++ makefile | 31 ++ makeopt | 170 +++++++++ maketarg | 90 +++++ models/player.dff | Bin 0 -> 77824 bytes models/player.txd | Bin 0 -> 67584 bytes options.mak | 12 + src/FileMgr.cpp | 158 ++++++++ src/FileMgr.h | 31 ++ src/Pad.cpp | 153 ++++++++ src/Pad.h | 31 ++ src/camera.c | 408 ++++++++++++++++++++ src/camera.h | 60 +++ src/common.h | 11 + src/main.cpp | 884 +++++++++++++++++++++++++++++++++++++++++++ src/skyfs.c | 738 ++++++++++++++++++++++++++++++++++++ src/skyfs.h | 38 ++ 23 files changed, 4488 insertions(+) create mode 100644 makecom/sky/cwppsky create mode 100644 makecom/sky/cwsky create mode 100644 makecom/sky/sky295 create mode 100644 makecom/sky/sky2953 create mode 100644 makecom/sky/skygcc create mode 100644 makecom/sky/skygpp create mode 100644 makecom/sky/skyprodg create mode 100644 makefile create mode 100644 makeopt create mode 100644 maketarg create mode 100755 models/player.dff create mode 100755 models/player.txd create mode 100644 options.mak create mode 100644 src/FileMgr.cpp create mode 100644 src/FileMgr.h create mode 100644 src/Pad.cpp create mode 100644 src/Pad.h create mode 100644 src/camera.c create mode 100644 src/camera.h create mode 100644 src/common.h create mode 100644 src/main.cpp create mode 100644 src/skyfs.c create mode 100644 src/skyfs.h diff --git a/makecom/sky/cwppsky b/makecom/sky/cwppsky new file mode 100644 index 0000000..e13f246 --- /dev/null +++ b/makecom/sky/cwppsky @@ -0,0 +1,241 @@ +########################################################################### +# +# File : makecom/cwsky +# +# Abstract : sky gcc specific compile time options. +# +# See +# o GCC homepage +# http://www.gnu.org/software/gcc +# o GCC compilations flags +# http://www.gnu.org/software/gcc/onlinedocs/gcc_2.html +# +# This file is included from a generic top level makefile when +# the Visual C compiler is selected +# +########################################################################### +# +# This file is a product of Criterion Software Ltd. +# +# This file is provided as is with no warranties of any kind and is +# provided without any obligation on Criterion Software Ltd. or Canon Inc. +# to assist in its use or modification. +# +# Criterion Software Ltd. will not, under any circumstances, be liable for +# any lost revenue or other damages arising from the use of this file. +# +# Copyright (c) 1999 Criterion Software Ltd. +# All Rights Reserved. +# +# RenderWare is a trademark of Canon Inc. +# +########################################################################### + +# Indicate that compiler options have been included +MAKECOM=1 + +ifeq ($(SMALLCODE), 1) +C_OPT = -O4,s +else +C_OPT = -O4,p +endif + +# by default, C optimisation is off when a C debug build is used. +ifndef COPTIMIZE +ifeq ($(CDEBUG), 1) +COPTIMIZE = 0 +else +COPTIMIZE = 1 +endif +endif + +ifeq ($(COPTIMIZE), 1) +CFLAGS += $(C_OPT) -DNDEBUG +else +CFLAGS += -O0 +#---------------- +# # gcc requires the generation of a dependency tree, and hence at least -O1, +# # to detect any use of uninitialized variables +# so build optimised then. Code generation options win. +endif + +ifeq ($(CDEBUG), 1) +CFLAGS += -g -prefix PREFIX_PS2_DEBUG.h +else +CFLAGS += -prefix PREFIX_PS2.h +endif + +ifeq ($(PG), 1) +CFLAGS += -pg -DPG +endif + +CFLAGS += -DRW_USE_SPF + +ifeq ($(SCE_11),1) +CFLAGS += -DSCE_11 +endif + +ifdef IOPPATH +CFLAGS += -DIOPPATH=$(IOPPATH) +endif + +# These seem to be platform specific, not compiler specific + +ifeq ($(NOASM), 1) +CFLAGS += -DNOASM +endif + +ifeq ("$(COMPILER)", "") +COMPILER=cc +endif + +ifeq ("$(LINKER)", "") +# It should be this, but we have a rather strange idea of LINKER +LINKER=link.exe +endif + +###### +# included burst from sony Makefiles +###### + +ifeq ("$(PS2_DRIVE)", "") +SCE = /usr/local/sce/ee +else +SCE = $(PS2_DRIVE):/usr/local/sce/ee +endif + +SCELIBDIR = $(SCE)/lib +SCEINCDIR = $(SCE)/include + +#PS2DIR = '$(subst \,/,$(patsubst %\license.dat,%, $(subst Program Files,Progra~1,$(LM_LICENSE_FILE))))/PS2Sup~1' +PS2DIR = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support' +PS2LIB = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Runtime/Libraries' + +# LCFILE = $(PS2DIR)/PS2LinkSegment.lcf +LCFILE = $(DEMODIR)/../../cwcommon/PS2LinkSegment.lcf + +ifeq ($(CDEBUG), 1) +MSLGCC_PS2_LIB = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE))/PS2 Support/Runtime/Libraries/MSLGCC_PS2D.LIB)' +else # ($(CDEBUG), 1) +MSLGCC_PS2_LIB = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE))/PS2 Support/Runtime/Libraries/MSLGCC_PS2.LIB)' +endif # ($(CDEBUG), 1) +ANSICPP_PS2_LIB= '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE))/PS2 Support/Msl/MSL_C++/MSL_MIPS/Lib/ANSICPP_PS2.LIB)' + +# RenderWare is a trademark of Canon Inc. + +SYSLIBS = \ + $(PS2DIR)/gcc_wrapper.c \ + $(SCELIBDIR)/libgraph.a \ + $(SCELIBDIR)/libdma.a \ + $(SCELIBDIR)/libdev.a \ + $(SCELIBDIR)/libpkt.a \ + $(SCELIBDIR)/libvu0.a \ + $(SCELIBDIR)/libmpeg.a \ + $(SCELIBDIR)/libipu.a \ + $(SCELIBDIR)/libpc.a \ + $(SCELIBDIR)/libkernl.a \ + $(SCELIBDIR)/libcdvd.a \ + $(SCELIBDIR)/liblout.a \ + $(SCELIBDIR)/libpad.a \ + $(SCELIBDIR)/libsdr.a \ + $(SCELIBDIR)/libssyn.a \ + $(SCELIBDIR)/libmc.a \ + $(SCELIBDIR)/libmsin.a \ + $(SCELIBDIR)/../gcc/ee/lib/libc.a \ + $(SCELIBDIR)/../gcc/ee/lib/libm.a \ + $(SCELIBDIR)/../gcc/lib/gcc-lib/ee/2.95.2/libgcc.a \ + $(MSLGCC_PS2_LIB) \ + $(ANSICPP_PS2_LIB) + +# $(SCELIBDIR)/../gcc/lib/gcc-lib/ee/2.9-ee-990721/libgcc.a \ + +CFLAGS += \ + -D__EXCEPTION__ \ + -D__NEW__ \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C++/MSL_Common/Include' \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C/MSL_Common/Include' \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C/MSL_MIPS/Include' \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C/MSL_MIPS/Include/cname' \ + -I$(PS2_DRIVE):/usr/local/sce/ee/include + +ifndef SCE_11 +SYSLIBS += $(SCELIBDIR)/libpad.a +endif + +ifeq ($(RWDEBUG), 1) +ifeq ($(RWMEMDEBUG), 1) +SYSLIBS += -L$(RWLIBDIR) -lrtdbmalloc +endif # ($(RWMEMDEBUG), 1) +endif # ($(RWDEBUG), 1) + +CWARNINGS = \ + +# -warn all \ +# -warn notinlined \ +# -warn pedantic \ +# -warn unused \ +# -warn unusedvar \ +# -warn noimplicit \ +# -warn nounusedarg +# +# # -warn dump + +CC = mwccps2 -dialect ec++ -msgstyle gcc -strict on -gccincludes +CPP = $(CC) +COUT = -o +LOUT = -e +SOUT = -S -o $@ +CPPOPT = -EP +CFLAGS += $(CWARNINGS) +CFLAGS += -c +CFLAGS += -DSKY +LD = mwccps2 --gcc-compat +LFLAGS = -I$(SCEINCDIR) -T $(LCFILE) -warn off -main ENTRYPOINT -g -nostartfiles -L$(SCE)/lib # -lm +LOUT = -o + +AS = asm_r5900_elf.exe +AOUT = -o +ASFLAGS = -c_preprocess -gnu # -w +ASFLAGS += -list $(OBJDIR)/$(basename $(notdir $<)).lsa + +DVPASM = ee-dvp-as +DVPASFLAGS = -I$(SRCDIR) -I$(DEVDIR)/$(RWTARGET) +DVPAOUT = -o + +RUN = dsedb -r run + +ifeq ($(CDEBUG), 1) +ASFLAGS += --gstabs +DVPASMFLAGS += --gstabs +endif + +# We do want assembler + +CFLAGS += -I$(SCE)/../common/include -I$(SCE)/include + +# Add crtO.o to list of object files + +OBJ += crt0.o + +VPATH += $(SCELIBDIR) + +# Define some compiler/platform specific parameters for the naming of object +# and library files + +O = o +L = a +LP = lib +EXE = .elf + +# Directory creation +ifndef MD +MD = mkdir -p +endif + +# The following rule is required, as it is not a default +#.SUFFIXES: .c .$(O) .asm .dsm + +$(OBJDIR)/%.$(O) : %.dsm + $(DVPASM) $(DVPASFLAGS) -alhs $(DVPAOUT)$@ $^ > $(OBJDIR)/$*.lsd + +CPPFLAGS += $(CFLAGS) diff --git a/makecom/sky/cwsky b/makecom/sky/cwsky new file mode 100644 index 0000000..cdd6f13 --- /dev/null +++ b/makecom/sky/cwsky @@ -0,0 +1,262 @@ +########################################################################### +# +# File : makecom/cwsky +# +# Abstract : sky gcc specific compile time options. +# +# See +# o GCC homepage +# http://www.gnu.org/software/gcc +# o GCC compilations flags +# http://www.gnu.org/software/gcc/onlinedocs/gcc_2.html +# +# This file is included from a generic top level makefile when +# the Visual C compiler is selected +# +########################################################################### +# +# This file is a product of Criterion Software Ltd. +# +# This file is provided as is with no warranties of any kind and is +# provided without any obligation on Criterion Software Ltd. or Canon Inc. +# to assist in its use or modification. +# +# Criterion Software Ltd. will not, under any circumstances, be liable for +# any lost revenue or other damages arising from the use of this file. +# +# Copyright (c) 1999 Criterion Software Ltd. +# All Rights Reserved. +# +# RenderWare is a trademark of Canon Inc. +# +########################################################################### + +# Indicate that compiler options have been included +MAKECOM=1 + +ifeq ($(SMALLCODE), 1) +C_OPT = -O4,s # -opt dump +else +C_OPT = -O4,p # -opt dump +endif + +# by default, C optimisation is off when a C debug build is used. +ifndef COPTIMIZE +ifeq ($(CDEBUG), 1) +COPTIMIZE = 0 +else +COPTIMIZE = 1 +endif +endif + +ifeq ($(COPTIMIZE), 1) +CFLAGS += $(C_OPT) -DNDEBUG +else +CFLAGS += -O0 +#---------------- +# # gcc requires the generation of a dependency tree, and hence at least -O1, +# # to detect any use of uninitialized variables +# so build optimised then. Code generation options win. +endif + +ifeq ($(CDEBUG), 1) +CFLAGS += -g -prefix PREFIX_PS2_DEBUG.h +else +CFLAGS += -prefix PREFIX_PS2.h +endif + +ifeq ($(PG), 1) +CFLAGS += -pg -DPG +endif + +CFLAGS += -DRW_USE_SPF + +ifeq ($(SCE_11),1) +CFLAGS += -DSCE_11 +endif + +ifdef IOPPATH +CFLAGS += -DIOPPATH=$(IOPPATH) +endif + +# These seem to be platform specific, not compiler specific + +ifeq ($(NOASM), 1) +CFLAGS += -DNOASM +endif + +ifeq ("$(COMPILER)", "") +COMPILER=cc +endif + +ifeq ("$(LINKER)", "") +# It should be this, but we have a rather strange idea of LINKER +LINKER=link.exe +endif + +###### +# included burst from sony Makefiles +###### + +ifeq ("$(PS2_DRIVE)", "") +SCE = /usr/local/sce/ee +else +SCE = $(PS2_DRIVE):/usr/local/sce/ee +endif + +SCELIBDIR = $(SCE)/lib +SCEINCDIR = $(SCE)/include + +#PS2DIR = '$(subst \,/,$(patsubst %\license.dat,%, $(subst Program Files,Progra~1,$(LM_LICENSE_FILE))))/PS2Sup~1' +PS2DIR = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support' +PS2LIB = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Runtime/Libraries' + +# LCFILE = $(PS2DIR)/PS2LinkSegment.lcf +LCFILE = $(DEMODIR)/../../cwcommon/PS2LinkSegment.lcf + + +###### +# The debug version of this seems to have been removed, so always use non-debug +#ifeq ($(CDEBUG), 1) +#MSLGCC_PS2_LIB = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE))/PS2 Support/Runtime/Libraries/MSLGCC_PS2D.LIB)' +#else # ($(CDEBUG), 1) +MSLGCC_PS2_LIB = '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE))/PS2 Support/Runtime/Libraries/MSLGCC_PS2.LIB)' +#endif # ($(CDEBUG), 1) +ANSICPP_PS2_LIB= '$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE))/PS2 Support/Msl/MSL_C++/MSL_MIPS/Lib/ANSICPP_PS2.LIB)' + +# RenderWare is a trademark of Canon Inc. + +SYSLIBS = \ + $(PS2DIR)/gcc_wrapper.c \ + $(SCELIBDIR)/libgraph.a \ + $(SCELIBDIR)/libdma.a \ + $(SCELIBDIR)/libdev.a \ + $(SCELIBDIR)/libpkt.a \ + $(SCELIBDIR)/libvu0.a \ + $(SCELIBDIR)/libmpeg.a \ + $(SCELIBDIR)/libipu.a \ + $(SCELIBDIR)/libpc.a \ + $(SCELIBDIR)/libkernl.a \ + $(SCELIBDIR)/libcdvd.a \ + $(SCELIBDIR)/liblout.a \ + $(SCELIBDIR)/libpad.a \ + $(SCELIBDIR)/libsdr.a \ + $(SCELIBDIR)/libssyn.a \ + $(SCELIBDIR)/libmc.a \ + $(SCELIBDIR)/libmsin.a \ + $(SCELIBDIR)/../gcc/ee/lib/libc.a \ + $(SCELIBDIR)/../gcc/ee/lib/libm.a \ + $(SCELIBDIR)/../gcc/lib/gcc-lib/ee/2.95.2/libgcc.a \ + $(MSLGCC_PS2_LIB) \ + $(ANSICPP_PS2_LIB) + +# $(SCELIBDIR)/../gcc/lib/gcc-lib/ee/2.9-ee-990721/libgcc.a \ + + +CFLAGS += \ + -D__EXCEPTION__ \ + -D__NEW__ \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C++/MSL_Common/Include' \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C/MSL_Common/Include' \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C/MSL_MIPS/Include' \ + -I'$(subst \,/,$(patsubst %\license.dat,%,$(LM_LICENSE_FILE)))/PS2 Support/Msl/MSL_C/MSL_MIPS/Include/cname' \ + -I$(PS2_DRIVE):/usr/local/sce/ee/include + + +ifndef SCE_11 +SYSLIBS += $(SCELIBDIR)/libpad.a +endif + +ifeq ($(RWDEBUG), 1) +ifeq ($(RWMEMDEBUG), 1) +SYSLIBS += -L$(RWLIBDIR) -lrtdbmalloc +endif # ($(RWMEMDEBUG), 1) +endif # ($(RWDEBUG), 1) + +CWARNINGS = \ + -warn all \ + -warn notinlined \ + -warn pedantic \ + -warn unused \ + -warn unusedvar \ + -warn noimplicit \ + -warn nounusedarg + +# -warn dump + +CC = mwccps2 --gcc-compat +CPP = $(CC) +COUT = -o +LOUT = -e +SOUT = -S -o $@ +CPPOPT = -E -P +CFLAGS += $(CWARNINGS) +CFLAGS += -c +CFLAGS += -DSKY +LD = mwccps2 --gcc-compat +LFLAGS = -I$(SCEINCDIR) -T $(LCFILE) -warn off -main ENTRYPOINT -g -nostartfiles -L$(SCE)/lib # -lm +LOUT = -o + +AS = asm_r5900_elf.exe +AOUT = -o +ASFLAGS = -c_preprocess -gnu # -w +ASFLAGS += -list $(OBJDIR)/$(basename $(notdir $<)).lsa + +DVPASM = ee-dvp-as +DVPASFLAGS = -I$(SRCDIR) -I$(DEVDIR)/$(RWTARGET) +DVPAOUT = -o + +RUN = dsedb -r run + +ifeq ($(CDEBUG), 1) +DVPASMFLAGS += --gstabs +else +ASFLAGS += -nodebug +endif + +# We do want assembler + +CFLAGS += -I$(SCE)/../common/include -I$(SCE)/include + +# Add crtO.o to list of object files + +OBJ += crt0.o + +VPATH += $(SCELIBDIR) + +# Define some compiler/platform specific parameters for the naming of object +# and library files + +O = o +L = a +LP = lib +EXE = .elf + +# Directory creation +ifndef MD +MD = mkdir -p +endif + +# Patch support +ifeq ($(RWPATCH), 1) +RWLIBS += \ + $(RWLIBDIR)/$(LP)rppatch.$(L) \ + $(RWLIBDIR)/$(LP)rtbezpat.$(L) +endif # ($(RWPATCH), 1) + +# Patch support +ifeq ($(RWPATCH), 1) +RWLIBS += \ + $(RWLIBDIR)/$(LP)rppatch.$(L) \ + $(RWLIBDIR)/$(LP)rtbezpat.$(L) +endif # ($(RWPATCH), 1) + +# The following rule is required, as it is not a default +#.SUFFIXES: .c .$(O) .asm .dsm + +$(OBJDIR)/%.$(O) : %.dsm + $(DVPASM) $(DVPASFLAGS) -alhs $(DVPAOUT)$@ $^ > $(OBJDIR)/$*.lsd + + + +CPPFLAGS += $(CFLAGS) diff --git a/makecom/sky/sky295 b/makecom/sky/sky295 new file mode 100644 index 0000000..5f0dff5 --- /dev/null +++ b/makecom/sky/sky295 @@ -0,0 +1,326 @@ +########################################################################### +# +# File : makecom/skygcc +# +# Abstract : sky gcc 2.95.2 specific compile time options. +# +# See +# o ee-gcc295 binaries +# http://www.snsys.com/files/psx2/gcc-2.95.2-ee-1.1-bin.zip +# o GCC homepage +# http://www.gnu.org/software/gcc +# o GCC compilations flags +# http://www.gnu.org/software/gcc/onlinedocs/gcc_2.html +# +########################################################################### +# +# This file is a product of Criterion Software Ltd. +# +# This file is provided as is with no warranties of any kind and is +# provided without any obligation on Criterion Software Ltd. or Canon Inc. +# to assist in its use or modification. +# +# Criterion Software Ltd. will not, under any circumstances, be liable for +# any lost revenue or other damages arising from the use of this file. +# +# Copyright (c) 1999 Criterion Software Ltd. +# All Rights Reserved. +# +# RenderWare is a trademark of Canon Inc. +# +########################################################################### + +# Indicate that compiler options have been included +MAKECOM=1 + +ifeq ($(SMALLCODE), 1) +C_OPT = -Os +else +C_OPT = -O3 +endif + +C_OPT += \ + -fcaller-saves \ + -fcse-follow-jumps \ + -fcse-skip-blocks \ + -fdelayed-branch \ + -fexpensive-optimizations \ + -ffast-math \ + -fgcse \ + -fmove-all-movables \ + -freduce-all-givs \ + -fregmove \ + -frerun-cse-after-loop \ + -frerun-loop-opt \ + -fschedule-insns2 \ + -fstrength-reduce \ + -fstrict-aliasing \ + -fthread-jumps \ + -funroll-loops + +# -fdata-sections \ +# -ffunction-sections \ + +# -fdelete-null-pointer-checks \ +# -foptimize-register-moves \ +# -fsingle-precision-constant \ +# -falign-functions=n \ +# -falign-jumps=n \ +# -falign-labels=n \ +# -falign-loops=n \ +# -fbranch-probabilities \ +# -fdce \ +# -ffloat-store \ +# -fforce-addr \ +# -fforce-mem \ +# -finline-functions \ +# -finline-limit=n \ +# -fkeep-inline-functions \ +# -fno-default-inline \ +# -fno-defer-pop \ +# -fno-function-cse \ +# -fno-inline \ +# -fno-math-errno \ +# -fno-peephole \ +# -fomit-frame-pointer \ +# -foptimize-sibling-calls \ +# -fschedule-insns \ +# -fssa \ +# -funroll-all-loops \ + + +# by default, C optimisation is off when a C debug build is used. +ifndef COPTIMIZE +ifeq ($(CDEBUG), 1) +COPTIMIZE = 0 +else +COPTIMIZE = 1 +endif +endif + +ifeq ($(COPTIMIZE), 1) +CFLAGS += $(C_OPT) -DNDEBUG -Wuninitialized +else +CFLAGS += -O0 +#---------------- +# # gcc requires the generation of a dependency tree, and hence at least -O1, +# # to detect any use of uninitialized variables +# so build optimised then. Code generation options win. +endif + +ifeq ($(CDEBUG), 1) +CFLAGS += -g +endif + +ifeq ($(PG), 1) +CFLAGS += -pg -DPG +endif + +CFLAGS += -DRW_USE_SPF + +ifeq ($(SCE_11),1) +CFLAGS += -DSCE_11 +endif + +ifdef IOPPATH +CFLAGS += -DIOPPATH=$(IOPPATH) +endif + +# These seem to be platform specific, not compiler specific + +ifeq ($(NOASM), 1) +CFLAGS += -DNOASM +endif + +ifeq ("$(COMPILER)", "") +COMPILER=cc +endif + +ifeq ("$(LINKER)", "") +# It should be this, but we have a rather strange idea of LINKER +LINKER=link.exe +endif + +###### +# included burst from sony Makefiles +###### + +ifeq ("$(PS2_DRIVE)", "") +SCE = /usr/local/sce/ee +else +SCE = $(PS2_DRIVE):/usr/local/sce/ee +endif + +SCELIBDIR = $(SCE)/lib +SCEINCDIR = $(SCE)/include + +ifeq ("$(SKYLCF)", "RWCMD") +LCFILE = $(DEMODIR)/../../makecom/sky/rwapp.cmd +else # ("$(RWLCF)", "") +LCFILE = $(SCELIBDIR)/app.cmd +endif # ("$(RWLCF)", "") + +SYSLIBS = $(SCELIBDIR)/libgraph.a \ + $(SCELIBDIR)/libdma.a + +ifndef SCE_11 +SYSLIBS += $(SCELIBDIR)/libpad.a +endif + +ifeq ($(RWDEBUG), 1) +ifeq ($(RWMEMDEBUG), 1) +SYSLIBS += -L$(RWLIBDIR) -lrtdbmalloc +endif # ($(RWMEMDEBUG), 1) +endif # ($(RWDEBUG), 1) + +CWARNINGS = \ + -W \ + -Wall \ + -Wcast-qual \ + -Wchar-subscripts \ + -Wcomment \ + -Werror-implicit-function-declaration \ + -Wformat \ + -Wimplicit \ + -Wimplicit-function-declaration \ + -Wimplicit-int \ + -Wimport \ + -Winline \ + -Wlong-long \ + -Wmain \ + -Wmissing-noreturn \ + -Wmultichar \ + -Wnested-externs \ + -Wno-import \ + -Wparentheses \ + -Wpointer-arith \ + -Wreturn-type \ + -Wsign-compare \ + -Wswitch \ + -Wtrigraphs \ + -Wunknown-pragmas \ + -Wunused \ + -Wwrite-strings + +# -Wbad-function-cast +# -Wredundant-decls +# -Wshadow +# -Wtraditional +# -Wundef +# -pedantic +# -Wmissing-declarations /* sce include files fire these warnings*/ +# -Wmissing-prototypes /* sce include files fire these warnings*/ +# -Wstrict-prototypes /* sce include files fire these warnings */ +# -w +# -Wcast-align +# -Wconversion +# -Wfloat-equal +# -Wpacked +# -Wpadded +# -Wunreachable-code +# -Wunused-function +# -Wunused-label +# -Wunused-parameter +# -Wunused-value +# -Wunused-variable +# -Waggregate-return +# -Werror +# -Wid-clash-len +# -Wlarger-than-len +# -fsyntax-only +# -Wbad-function-cast +# -Wredundant-decls +# -Wshadow +# -Wtraditional +# -Wundef +# -pedantic +# -Wmissing-declarations /* sce include files fire these warnings*/ +# -Wmissing-prototypes /* sce include files fire these warnings*/ +# -Wstrict-prototypes /* sce include files fire these warnings */ +# -w +# -Wcast-align +# -Wconversion +# -Wfloat-equal +# -Wpacked +# -Wpadded +# -Wunreachable-code +# -Wunused-function +# -Wunused-label +# -Wunused-parameter +# -Wunused-value +# -Wunused-variable +# -Waggregate-return +# -Werror +# -Wid-clash-len +# -Wlarger-than-len +# -fsyntax-only + +CC = ee-gcc295 +CPP = $(CC) +COUT = -o +LOUT = -e +SOUT = -S -o $@ +CPPOPT = -E -P +CFLAGS += $(CWARNINGS) -fno-common -c +CFLAGS += -Wa,-I$(DEVDIR)/$(RWTARGET) +CFLAGS += -Wa,-al=$*.lst +CFLAGS += -DSKY +LD = ee-gcc295 -Q # -Q seems to avoid temporary file race conditions +LFLAGS = -T $(LCFILE) -g -Wl,-Map,$(TARGET).map -nostartfiles -L$(SCELIBDIR) -lm +LOUT = -o + +AS = ee-gcc295 -Q # -Q seems to avoid temporary file race conditions +AOUT = -o +ASFLAGS = -c -xassembler-with-cpp +ASFLAGS += -Wa,-al=$*.lsa + +DVPASM = ee-dvp-as +DVPASFLAGS = -I$(SRCDIR) -I$(DEVDIR)/$(RWTARGET) +DVPAOUT = -o + +RUN = dsedb -r run + +ifeq ($(CDEBUG), 1) +ASFLAGS += --gstabs +DVPASMFLAGS += --gstabs +endif + +# We do want assembler + +CFLAGS += -I/usr/local/sce/common/include -I/usr/local/sce/ee/include +CFLAGS += -fno-rtti -fno-exceptions + + +# Add crtO.o to list of object files + +OBJ += crt0.o + +VPATH += $(SCELIBDIR) + +# Define some compiler/platform specific parameters for the naming of object +# and library files + +O = o +L = a +LP = lib +EXE = .elf + +# Directory creation +ifndef MD +MD = mkdir -p +endif + +# Patch support +ifeq ($(RWPATCH), 1) +RWLIBS += \ + $(RWLIBDIR)/$(LP)rppatch.$(L) \ + $(RWLIBDIR)/$(LP)rtbezpat.$(L) +endif # ($(RWPATCH), 1) + +# The following rule is required, as it is not a default + +#.SUFFIXES: .c .$(O) .asm .dsm + +$(OBJDIR)/%.$(O) : %.dsm + $(DVPASM) $(DVPASFLAGS) -alhs $(DVPAOUT)$@ $^ > $(OBJDIR)/$*.lsd +CPPFLAGS += $(CFLAGS) diff --git a/makecom/sky/sky2953 b/makecom/sky/sky2953 new file mode 100644 index 0000000..eaca9d1 --- /dev/null +++ b/makecom/sky/sky2953 @@ -0,0 +1,323 @@ +########################################################################### +# +# File : makecom/skygcc +# +# Abstract : sky gcc 2.95.3 specific compile time options. +# +# See +# o ee-gcc2953 binaries +# http://www.snsys.com/files/psx2/Temp/ps2-ee-2.95.3-v1.01.zip +# o GCC homepage +# http://www.gnu.org/software/gcc/gcc-2.95/gcc-2.95.3.html +# +########################################################################### +# +# This file is a product of Criterion Software Ltd. +# +# This file is provided as is with no warranties of any kind and is +# provided without any obligation on Criterion Software Ltd. or Canon Inc. +# to assist in its use or modification. +# +# Criterion Software Ltd. will not, under any circumstances, be liable for +# any lost revenue or other damages arising from the use of this file. +# +# Copyright (c) 1999 Criterion Software Ltd. +# All Rights Reserved. +# +# RenderWare is a trademark of Canon Inc. +# +########################################################################### + +# Indicate that compiler options have been included +MAKECOM=1 + +ifeq ($(SMALLCODE), 1) +C_OPT = -Os +else +C_OPT = -O3 +endif + +C_OPT += \ + -fcaller-saves \ + -fcse-follow-jumps \ + -fcse-skip-blocks \ + -fdelayed-branch \ + -fexpensive-optimizations \ + -ffast-math \ + -fgcse \ + -fmove-all-movables \ + -freduce-all-givs \ + -fregmove \ + -frerun-cse-after-loop \ + -frerun-loop-opt \ + -fschedule-insns2 \ + -fstrength-reduce \ + -fstrict-aliasing \ + -fthread-jumps \ + -funroll-loops + +# -fdata-sections \ +# -ffunction-sections \ + +# -fdelete-null-pointer-checks \ +# -foptimize-register-moves \ +# -fsingle-precision-constant \ +# -falign-functions=n \ +# -falign-jumps=n \ +# -falign-labels=n \ +# -falign-loops=n \ +# -fbranch-probabilities \ +# -fdce \ +# -ffloat-store \ +# -fforce-addr \ +# -fforce-mem \ +# -finline-functions \ +# -finline-limit=n \ +# -fkeep-inline-functions \ +# -fno-default-inline \ +# -fno-defer-pop \ +# -fno-function-cse \ +# -fno-inline \ +# -fno-math-errno \ +# -fno-peephole \ +# -fomit-frame-pointer \ +# -foptimize-sibling-calls \ +# -fschedule-insns \ +# -fssa \ +# -funroll-all-loops \ + + +# by default, C optimisation is off when a C debug build is used. +ifndef COPTIMIZE +ifeq ($(CDEBUG), 1) +COPTIMIZE = 0 +else +COPTIMIZE = 1 +endif +endif + +ifeq ($(COPTIMIZE), 1) +CFLAGS += $(C_OPT) -DNDEBUG -Wuninitialized +else +CFLAGS += -O0 +#---------------- +# # gcc requires the generation of a dependency tree, and hence at least -O1, +# # to detect any use of uninitialized variables +# so build optimised then. Code generation options win. +endif + +ifeq ($(CDEBUG), 1) +CFLAGS += -g +endif + +ifeq ($(PG), 1) +CFLAGS += -pg -DPG +endif + +CFLAGS += -DRW_USE_SPF + +ifeq ($(SCE_11),1) +CFLAGS += -DSCE_11 +endif + +ifdef IOPPATH +CFLAGS += -DIOPPATH=$(IOPPATH) +endif + +# These seem to be platform specific, not compiler specific + +ifeq ($(NOASM), 1) +CFLAGS += -DNOASM +endif + +ifeq ("$(COMPILER)", "") +COMPILER=cc +endif + +ifeq ("$(LINKER)", "") +# It should be this, but we have a rather strange idea of LINKER +LINKER=link.exe +endif + +###### +# included burst from sony Makefiles +###### + +ifeq ("$(PS2_DRIVE)", "") +SCE = /usr/local/sce/ee +else +SCE = $(PS2_DRIVE):/usr/local/sce/ee +endif + +SCELIBDIR = $(SCE)/lib +SCEINCDIR = $(SCE)/include + +ifeq ("$(SKYLCF)", "RWCMD") +LCFILE = $(DEMODIR)/../../makecom/sky/rwapp.cmd +else # ("$(RWLCF)", "") +LCFILE = $(SCELIBDIR)/app.cmd +endif # ("$(RWLCF)", "") + +SYSLIBS = $(SCELIBDIR)/libgraph.a \ + $(SCELIBDIR)/libdma.a + +ifndef SCE_11 +SYSLIBS += $(SCELIBDIR)/libpad.a +endif + +ifeq ($(RWDEBUG), 1) +ifeq ($(RWMEMDEBUG), 1) +SYSLIBS += -L$(RWLIBDIR) -lrtdbmalloc +endif # ($(RWMEMDEBUG), 1) +endif # ($(RWDEBUG), 1) + +CWARNINGS = \ + -W \ + -Wall \ + -Wcast-qual \ + -Wchar-subscripts \ + -Wcomment \ + -Werror-implicit-function-declaration \ + -Wformat \ + -Wimplicit \ + -Wimplicit-function-declaration \ + -Wimplicit-int \ + -Wimport \ + -Winline \ + -Wlong-long \ + -Wmain \ + -Wmissing-noreturn \ + -Wmultichar \ + -Wnested-externs \ + -Wno-import \ + -Wparentheses \ + -Wpointer-arith \ + -Wreturn-type \ + -Wsign-compare \ + -Wswitch \ + -Wtrigraphs \ + -Wunknown-pragmas \ + -Wunused \ + -Wwrite-strings + +# -Wbad-function-cast +# -Wredundant-decls +# -Wshadow +# -Wtraditional +# -Wundef +# -pedantic +# -Wmissing-declarations /* sce include files fire these warnings*/ +# -Wmissing-prototypes /* sce include files fire these warnings*/ +# -Wstrict-prototypes /* sce include files fire these warnings */ +# -w +# -Wcast-align +# -Wconversion +# -Wfloat-equal +# -Wpacked +# -Wpadded +# -Wunreachable-code +# -Wunused-function +# -Wunused-label +# -Wunused-parameter +# -Wunused-value +# -Wunused-variable +# -Waggregate-return +# -Werror +# -Wid-clash-len +# -Wlarger-than-len +# -fsyntax-only +# -Wbad-function-cast +# -Wredundant-decls +# -Wshadow +# -Wtraditional +# -Wundef +# -pedantic +# -Wmissing-declarations /* sce include files fire these warnings*/ +# -Wmissing-prototypes /* sce include files fire these warnings*/ +# -Wstrict-prototypes /* sce include files fire these warnings */ +# -w +# -Wcast-align +# -Wconversion +# -Wfloat-equal +# -Wpacked +# -Wpadded +# -Wunreachable-code +# -Wunused-function +# -Wunused-label +# -Wunused-parameter +# -Wunused-value +# -Wunused-variable +# -Waggregate-return +# -Werror +# -Wid-clash-len +# -Wlarger-than-len +# -fsyntax-only + +CC = ee-gcc2953 # -Q seems to avoid temporary file race conditions +CPP = $(CC) +COUT = -o +LOUT = -e +SOUT = -S -o $@ +CPPOPT = -E -P +CFLAGS += $(CWARNINGS) -fno-common -c +CFLAGS += -Wa,-I$(DEVDIR)/$(RWTARGET) +CFLAGS += -Wa,-al=$*.lst +CFLAGS += -DSKY +LD = ee-gcc2953 # -Q seems to avoid temporary file race conditions +LFLAGS = -T $(LCFILE) -g -Wl,-Map,$(TARGET).map -nostartfiles -L$(SCELIBDIR) -lm +LOUT = -o + +AS = ee-gcc2953 # -Q seems to avoid temporary file race conditions +AOUT = -o +ASFLAGS = -c -xassembler-with-cpp +ASFLAGS += -Wa,-al=$*.lsa + +DVPASM = ee-dvp-as +DVPASFLAGS = -I$(SRCDIR) -I$(DEVDIR)/$(RWTARGET) +DVPAOUT = -o + +RUN = dsedb -r run + +ifeq ($(CDEBUG), 1) +ASFLAGS += --gstabs +DVPASMFLAGS += --gstabs +endif + +# We do want assembler + +CFLAGS += -I/usr/local/sce/common/include -I/usr/local/sce/ee/include +CFLAGS += -fno-rtti -fno-exceptions + +# Add crtO.o to list of object files + +OBJ += crt0.o + +VPATH += $(SCELIBDIR) + +# Define some compiler/platform specific parameters for the naming of object +# and library files + +O = o +L = a +LP = lib +EXE = .elf + +# Directory creation +ifndef MD +MD = mkdir -p +endif + +# Patch support +ifeq ($(RWPATCH), 1) +RWLIBS += \ + $(RWLIBDIR)/$(LP)rppatch.$(L) \ + $(RWLIBDIR)/$(LP)rtbezpat.$(L) +endif # ($(RWPATCH), 1) + +# The following rule is required, as it is not a default + +#.SUFFIXES: .c .$(O) .asm .dsm + +$(OBJDIR)/%.$(O) : %.dsm + $(DVPASM) $(DVPASFLAGS) -alhs $(DVPAOUT)$@ $^ > $(OBJDIR)/$*.lsd +CPPFLAGS += $(CFLAGS) diff --git a/makecom/sky/skygcc b/makecom/sky/skygcc new file mode 100644 index 0000000..7f5d2c9 --- /dev/null +++ b/makecom/sky/skygcc @@ -0,0 +1,276 @@ +########################################################################### +# +# File : makecom/skygcc +# +# Abstract : sky gcc specific compile time options. +# +# See +# o GCC homepage +# http://www.gnu.org/software/gcc +# o GCC compilations flags +# http://www.gnu.org/software/gcc/onlinedocs/gcc_2.html +# +# This file is included from a generic top level makefile when +# using the Linux hosted Sony tool chain. It may also be used +# with PC builds of the Sony tools. +# +########################################################################### +# +# This file is a product of Criterion Software Ltd. +# +# This file is provided as is with no warranties of any kind and is +# provided without any obligation on Criterion Software Ltd. or Canon Inc. +# to assist in its use or modification. +# +# Criterion Software Ltd. will not, under any circumstances, be liable for +# any lost revenue or other damages arising from the use of this file. +# +# Copyright (c) 1999 Criterion Software Ltd. +# All Rights Reserved. +# +# RenderWare is a trademark of Canon Inc. +# +########################################################################### + +# Indicate that compiler options have been included +MAKECOM=1 + +CC = ee-gcc + +# +# Sony tool chain 2.96 requires a slightly different config to the +# older ones. The following lets us sellect. +# +CC_VER := $(shell $(CC) -dumpversion) +CC_VER := $(findstring 2.96, $(CC_VER)) + +ifeq ($(SMALLCODE), 1) +C_OPT = -Os +else +C_OPT = -O3 +endif + +# by default, C optimisation is off when a C debug build is used. +ifndef COPTIMIZE +ifeq ($(CDEBUG), 1) +COPTIMIZE = 0 +else +COPTIMIZE = 1 +endif +endif + +ifeq ($(COPTIMIZE), 1) +CFLAGS += $(C_OPT) -DNDEBUG -Wuninitialized +else +CFLAGS += -O0 +#---------------- +# # gcc requires the generation of a dependency tree, and hence at least -O1, +# # to detect any use of uninitialized variables +# so build optimised then. Code generation options win. +endif + +ifeq ($(CDEBUG), 1) +CFLAGS += -g +endif + +ifeq ($(PG), 1) +CFLAGS += -pg -DPG +endif + +CFLAGS += -DRW_USE_SPF + +ifeq ($(SCE_11),1) +CFLAGS += -DSCE_11 +endif + +ifdef IOPPATH +CFLAGS += -DIOPPATH=$(IOPPATH) +endif + +# These seem to be platform specific, not compiler specific + +ifeq ($(NOASM), 1) +CFLAGS += -DNOASM +endif + +ifeq ("$(COMPILER)", "") +COMPILER=cc +endif + +ifeq ("$(LINKER)", "") +# It should be this, but we have a rather strange idea of LINKER +LINKER=link.exe +endif + +###### +# included burst from sony Makefiles +###### + +ifeq ("$(PS2_DRIVE)", "") +SCE = /usr/local/sce/ee +else +SCE = $(PS2_DRIVE):/usr/local/sce/ee +endif + +SCELIBDIR = $(SCE)/lib +SCEINCDIR = $(SCE)/include + +ifeq ("$(SKYLCF)", "RWCMD") +LCFILE = $(DEMODIR)/../../makecom/sky/rwapp.cmd +else # ("$(RWLCF)", "") +LCFILE = $(SCELIBDIR)/app.cmd +endif # ("$(RWLCF)", "") + +SYSLIBS = $(SCELIBDIR)/libgraph.a \ + $(SCELIBDIR)/libdma.a + +ifndef SCE_11 +SYSLIBS += $(SCELIBDIR)/libpad.a +endif + +ifeq ($(RWDEBUG), 1) +ifeq ($(RWMEMDEBUG), 1) +SYSLIBS += -L$(RWLIBDIR) -lrtdbmalloc +endif # ($(RWMEMDEBUG), 1) +endif # ($(RWDEBUG), 1) + +CWARNINGS = \ + -Wall \ + -W \ + -Wcast-qual \ + -Wchar-subscripts \ + -Wcomment \ + -Wformat \ + -Wimplicit \ + -Wimplicit-function-declaration \ + -Wimplicit-int \ + -Winline \ + -Wlong-long \ + -Wmain \ + -Wmissing-noreturn \ + -Wmultichar \ + -Wnested-externs \ + -Wparentheses \ + -Wpointer-arith \ + -Wreturn-type \ + -Wsign-compare \ + -Wswitch \ + -Wtrigraphs \ + -Wunknown-pragmas \ + -Wunused \ + -Wwrite-strings + +# -Wid-clash-32 \ +# -ansi +# -pedantic +# -Waggregate-return +# -Wbad-function-cast +# -Wcast-align +# -Wconversion +# -Werror +# -Wlarger-than-len +# -Wmissing-declarations /* sce include files fire these warnings*/ +# -Wmissing-prototypes /* sce include files fire these warnings*/ +# -Wredundant-decls +# -Wshadow +# -Wstrict-prototypes /* sce include files fire these warnings */ +# -Wtraditional +# -Wundef +# -Wuninitialized + +CPP = $(CC) +COUT = -o +LOUT = -e +SOUT = -S -o $@ +CPPOPT = -E -P +CFLAGS += $(CWARNINGS) -fno-common -c +CFLAGS += -Wa,-I$(DEVDIR)/$(RWTARGET) +#CFLAGS += -Wa,-al=$*.lst +CFLAGS += -DSKY +LD = ee-gcc +LFLAGS = -T $(LCFILE) -g -Wl,-Map,$(TARGET).map -L$(SCELIBDIR) -lm + +ifeq ("$(CC_VER)", "2.96") +LFLAGS += -mno-crt0 +else +LFLAGS += -nostartfiles +endif + +LOUT = -o + +AS = ee-gcc +AOUT = -o +ASFLAGS = -c -xassembler-with-cpp +#ASFLAGS += -Wa,-al=$*.lsa + +DVPASM = ee-dvp-as +DVPASFLAGS = -I$(SRCDIR) -I$(DEVDIR)/$(RWTARGET) +DVPAOUT = -o + +RUN = dsedb -r run + +ifeq ($(CDEBUG), 1) +ASFLAGS += --gstabs +DVPASMFLAGS += --gstabs +endif + +# We do want assembler + +CFLAGS += -I/usr/local/sce/common/include -I/usr/local/sce/ee/include +CFLAGS += -fno-exceptions + + +# Add crtO.o to list of object files + +OBJ += crt0.o + +VPATH += $(SCELIBDIR) + +# Define some compiler/platform specific parameters for the naming of object +# and library files + +O = o +L = a +LP = lib +EXE = .elf + +# Directory creation +ifndef MD +MD = mkdir -p +endif + +# Patch support +ifeq ($(RWPATCH), 1) +RWLIBS += \ + $(RWLIBDIR)/$(LP)rppatch.$(L) \ + $(RWLIBDIR)/$(LP)rtbezpat.$(L) +endif # ($(RWPATCH), 1) + +# The following rule is required, as it is not a default + +#.SUFFIXES: .c .$(O) .asm .dsm + +$(OBJDIR)/%.$(O) : %.dsm + $(DVPASM) $(DVPASFLAGS) -alhs $(DVPAOUT)$@ $^ > $(OBJDIR)/$*.lsd + +CPPFLAGS += $(CFLAGS) + +CPPFLAGS += \ + -Wctor-dtor-privacy \ + -Wno-non-template-friend \ + -Wno-pmf-conversions \ + -Wnon-virtual-dtor \ + -Woverloaded-virtual \ + -Wreorder \ + -Wsign-promo \ + -Wsynth + +# -Weffc++ +# -Wold-style-cast + + + + + + +CXX = ee-g++ diff --git a/makecom/sky/skygpp b/makecom/sky/skygpp new file mode 100644 index 0000000..3844942 --- /dev/null +++ b/makecom/sky/skygpp @@ -0,0 +1,8 @@ +########################################## +# These are for gcc in the sky cross env # +# running in c++ mode # +########################################## + +CFLAGS += -x c++ + +include $(RWSDK)/../app/makecom/sky/sky2953 diff --git a/makecom/sky/skyprodg b/makecom/sky/skyprodg new file mode 100644 index 0000000..c411eb2 --- /dev/null +++ b/makecom/sky/skyprodg @@ -0,0 +1,237 @@ +########################################################################### +# +# File : makecom/skygcc +# +# Abstract : sky gcc specific compile time options. +# +# See +# o GCC homepage +# http://www.gnu.org/software/gcc +# o GCC compilations flags +# http://www.gnu.org/software/gcc/onlinedocs/gcc_2.html +# +# This file is included from a generic top level makefile when +# the Visual C compiler is selected +# +########################################################################### +# +# This file is a product of Criterion Software Ltd. +# +# This file is provided as is with no warranties of any kind and is +# provided without any obligation on Criterion Software Ltd. or Canon Inc. +# to assist in its use or modification. +# +# Criterion Software Ltd. will not, under any circumstances, be liable for +# any lost revenue or other damages arising from the use of this file. +# +# Copyright (c) 1999 Criterion Software Ltd. +# All Rights Reserved. +# +# RenderWare is a trademark of Canon Inc. +# +########################################################################### + +# Indicate that compiler options have been included +MAKECOM=1 + +ifeq ($(SMALLCODE), 1) +C_OPT = -Os +else +C_OPT = -O3 +endif + +# by default, C optimisation is off when a C debug build is used. +ifndef COPTIMIZE +ifeq ($(CDEBUG), 1) +COPTIMIZE = 0 +else +COPTIMIZE = 1 +endif +endif + +ifeq ($(COPTIMIZE), 1) +CFLAGS += $(C_OPT) -DNDEBUG -Wuninitialized +else +CFLAGS += -O0 +#---------------- +# # gcc requires the generation of a dependency tree, and hence at least -O1, +# # to detect any use of uninitialized variables +# so build optimised then. Code generation options win. +endif + +ifeq ($(CDEBUG), 1) +CFLAGS += -g +endif + +ifeq ($(PG), 1) +CFLAGS += -pg -DPG +endif + +CFLAGS += -DRW_USE_SPF + +ifeq ($(SCE_11),1) +CFLAGS += -DSCE_11 +endif + +ifeq ($(RWDEBUG), 1) +ifeq ($(RWMEMDEBUG), 1) +RWLIBS += $(RWLIBDIR)/$(LP)rtmemdbg.$(L) +endif # ($(RWMEMDEBUG), 1) +endif # ($(RWDEBUG), 1) + +ifdef IOPPATH +CFLAGS += -DIOPPATH=$(IOPPATH) +endif + +# These seem to be platform specific, not compiler specific + +ifeq ($(NOASM), 1) +CFLAGS += -DNOASM +endif + +ifeq ("$(COMPILER)", "") +COMPILER=cc +endif + +ifeq ("$(LINKER)", "") +# It should be this, but we have a rather strange idea of LINKER +LINKER=link.exe +endif + +###### +# included burst from sony Makefiles +###### + +SCE = /usr/local/sce/ee +SCELIBDIR = $(SCE)/lib +SCEINCDIR = $(SCE)/include + + +LCFILE = $(PS2_DRIVE):$(SCELIBDIR)/ps2.lk + +SYSLIBS = $(PS2_DRIVE):$(SCELIBDIR)/libgraph.a \ + $(PS2_DRIVE):$(SCELIBDIR)/libdma.a \ + $(PS2_DRIVE):$(SCELIBDIR)/libdev.a \ + $(PS2_DRIVE):$(SCELIBDIR)/libpkt.a \ + $(PS2_DRIVE):$(SCELIBDIR)/libvu0.a + +ifndef SCE_11 +SYSLIBS += $(PS2_DRIVE):$(SCELIBDIR)/libpad.a +endif + +CWARNINGS = \ + -Wall \ + -W \ + -Wcast-qual \ + -Wchar-subscripts \ + -Wcomment \ + -Wformat \ + -Wid-clash-32 \ + -Wimplicit \ + -Wimplicit-function-declaration \ + -Wimplicit-int \ + -Winline \ + -Wlong-long \ + -Wmain \ + -Wmissing-noreturn \ + -Wmultichar \ + -Wnested-externs \ + -Wparentheses \ + -Wpointer-arith \ + -Wreturn-type \ + -Wsign-compare \ + -Wswitch \ + -Wtrigraphs \ + -Wunknown-pragmas \ + -Wunused \ + -Wwrite-strings + +# -ansi +# -pedantic +# -Waggregate-return +# -Wbad-function-cast +# -Wcast-align +# -Wconversion +# -Werror +# -Wlarger-than-len +# -Wmissing-declarations /* sce include files fire these warnings*/ +# -Wmissing-prototypes /* sce include files fire these warnings*/ +# -Wredundant-decls +# -Wshadow +# -Wstrict-prototypes /* sce include files fire these warnings */ +# -Wtraditional +# -Wundef +# -Wuninitialized + +CC = ee-gcc +CPP = $(CC) +COUT = -o +LOUT = -e +SOUT = -S -o $@ +CPPOPT = -E -P +CFLAGS += $(CWARNINGS) -fno-common -c +CFLAGS += -Wa,-I$(DEVDIR)/$(RWTARGET) +CFLAGS += -Wa,-al=$*.lst +CFLAGS += -DSKY +LD = ps2link +LFLAGS = \ + -verbose -c \ + -l $(PS2_DRIVE):$(SCELIBDIR) \ + -l $(PS2_DRIVE):$(SCE)/gcc/ee/lib \ + -l $(PS2_DRIVE):$(SCE)/gcc/lib/gcc-lib/ee/2.9-ee-990721 \ + @$(LCFILE),$(PROJS),$(PROJS).map +LOUT = -o + +AS = ee-gcc +AOUT = -o +ASFLAGS = -c -xassembler-with-cpp +ASFLAGS += -Wa,-al=$*.lsa + +DVPASM = ee-dvp-as +DVPASFLAGS = -I$(SRCDIR) -I$(DEVDIR)/$(RWTARGETcomp) +DVPAOUT = -o + +RUN = dsedb -r run + +ifeq ($(CDEBUG), 1) +ASFLAGS += --gstabs +DVPASMFLAGS += --gstabs +endif + +# We do want assembler + +CFLAGS += -I$(SCEINCDIR) +CFLAGS += -fno-rtti -fno-exceptions + +# Add crtO.o to list of object files + +OBJ += crt0.o + +VPATH += $(SCELIBDIR) + +# Define some compiler/platform specific parameters for the naming of object +# and library files + +O = o +L = a +LP = lib +EXE = .elf + +# Directory creation +ifndef MD +MD = mkdir -p +endif + +# Patch support +ifeq ($(RWPATCH), 1) +RWLIBS += \ + $(RWLIBDIR)/$(LP)rppatch.$(L) \ + $(RWLIBDIR)/$(LP)rtbezpat.$(L) +endif # ($(RWPATCH), 1) + +#.SUFFIXES: .c .$(O) .asm .dsm + +$(OBJDIR)/%.$(O) : %.dsm + $(DVPASM) $(DVPASFLAGS) -alhs $(DVPAOUT)$@ $^ > $(OBJDIR)/$*.lsd +CPPFLAGS += $(CFLAGS) + diff --git a/makefile b/makefile new file mode 100644 index 0000000..9e13360 --- /dev/null +++ b/makefile @@ -0,0 +1,31 @@ +# Define the projects to be built + +DEMO = rwtest + +# include common makefile options + +include makeopt + +CXXSRC = $(SRC)/main.cpp \ + $(SRC)/Pad.cpp \ + $(SRC)/FileMgr.cpp \ + +CSRC = $(SRC)/camera.c \ + $(SRC)/skyfs.c \ + +#CSRC += $(SKELSRC) + +ifeq ($(RWMETRICS), 1) +CSRC += $(SKEL)/vecfont.c \ + $(SKEL)/metrics.c +endif + +RWLIBS += $(RWLIBDIR)/$(LP)rtcharse.$(L) \ + $(RWLIBDIR)/$(LP)rpworld.$(L) \ + $(RWLIBDIR)/$(LP)rwcore.$(L) + +SYSLIBS += $(SCELIBDIR)/libcdvd.a + +include maketarg + + diff --git a/makeopt b/makeopt new file mode 100644 index 0000000..0cb6fa4 --- /dev/null +++ b/makeopt @@ -0,0 +1,170 @@ +# put a default target at the top to prevent rules from getting confused later + +all: demo + +# +# include user custom options file if it exists +# +ifndef RWOPTIONS +RWOPTIONS = options.mak +endif +include $(RWOPTIONS) + +ifndef RWSIMD +RWSIMD = 0 +endif + +ifndef RWVERBOSE +RWVERBOSE = 0 +endif + +ifndef RWSUPPRESSINLINE +RWSUPPRESSINLINE = 0 +endif + +ifndef RWSUPPRESSOPTIMIZATIONPRAGMAS +RWSUPPRESSOPTIMIZATIONPRAGMAS = 0 +endif + +ifeq ($(RWFULLPLATFORM), 1) +RWPLATFORM = $(RWOS)/$(RWCOMPILER)/$(RWTARGET) +RWPLATFORMEXE = $(RWOS)_$(RWCOMPILER)_$(RWTARGET) +else +RWPLATFORM = $(RWTARGET) +RWPLATFORMEXE = $(RWTARGET) +endif # ifeq ($(RWFULLPLATFORM), 1) + +# all directories are defined relative to DEMODIR +ifndef DEMODIR +DEMODIR = $(CURDIR) +# setting BASDEIR=$(CURDIR) enables absolute path names +# which makes a better job of debug symbols for profiling. debugging etc. +# see also http://www.fsf.org/software/make/make.html +endif + +# RWOUTPUT +ifeq ("$(RWOUTPUT)", "") +RWLIBPATH = $(RWSDK)/lib/$(RWPLATFORM) +else +RWLIBPATH = $(RWSDK)/lib/$(RWPLATFORM)/$(RWOUTPUT) +endif + +ifeq ($(RWMETRICS), 1) +RWLIBDIR = $(RWLIBPATH)/metrics +ifeq ("$(RWOUTPUT)", "") +OBJDIR = obj/$(RWPLATFORM)m +else +OBJDIR = obj/$(RWPLATFORM)m/$(RWOUTPUT) +endif +CFLAGS += -DRWMETRICS +PROJS = $(DEMO)_$(RWPLATFORMEXE)m$(EXE) +else # RWMETRICS +ifeq ($(RWDEBUG), 1) +RWLIBDIR = $(RWLIBPATH)/debug +ifeq ("$(RWOUTPUT)", "") +OBJDIR = obj/$(RWPLATFORM)d +else +OBJDIR = obj/$(RWPLATFORM)d/$(RWOUTPUT) +endif +CFLAGS += -DRWDEBUG +PROJS = $(DEMO)_$(RWPLATFORMEXE)d$(EXE) +else # RWDEBUG +ifeq ($(CPROFILE), 1) +RWLIBDIR = $(RWLIBPATH)/profile +ifeq ("$(RWOUTPUT)", "") +OBJDIR = obj/$(RWPLATFORM)p +else +OBJDIR = obj/$(RWPLATFORM)p/$(RWOUTPUT) +endif +CFLAGS += -DCPROFILE +PROJS = $(DEMO)_$(RWPLATFORMEXE)p$(EXE) +else # CPROFILE +ifeq ($(MSWST), 1) +RWLIBDIR = $(RWLIBPATH)/mswst +ifeq ("$(RWOUTPUT)", "") +OBJDIR = obj/$(RWPLATFORM)wst +else +OBJDIR = obj/$(RWPLATFORM)wst/$(RWOUTPUT) +endif +PROJS = $(DEMO)_$(RWPLATFORMEXE)wst$(EXE) +else # MSWS +RWLIBDIR = $(RWLIBPATH) +ifeq ("$(RWOUTPUT)", "") +OBJDIR = obj/$(RWPLATFORM) +else +OBJDIR = obj/$(RWPLATFORM)/$(RWOUTPUT) +endif +PROJS = $(DEMO)_$(RWPLATFORMEXE)$(EXE) +endif # MSWST +endif # CPROFILE +endif # RWDEBUG +endif # RWMETRICS + +ifeq ("$(RWTARGET)", "xbox") +XBOXPROJS = $(patsubst %$(EXE),%.xbe,$(PROJS)) +endif + +ifeq ($(RWPATCH), 1) +CFLAGS += -DRWPATCH +endif + +ifeq ($(RWMEMDEBUG), 1) +CFLAGS += -DRWMEMDEBUG +endif + +ifeq ($(RWSIMD), 1) +CFLAGS += -DRWSIMD +endif + +ifeq ($(RWVERBOSE), 1) +CFLAGS += -DRWVERBOSE +endif + +ifeq ($(RWSUPPRESSINLINE), 1) +CFLAGS += -DRWSUPPRESSINLINE +endif + +ifeq ($(RWSUPPRESSOPTIMIZATIONPRAGMAS), 1) +CFLAGS += -DRWSUPPRESSOPTIMIZATIONPRAGMAS +endif + +RWINCDIR = $(RWSDK)/include/$(RWPLATFORM) + +# Define Common Directories & Files + +SKEL = $(DEMODIR)/skel +SKELPS = $(SKEL)/$(RWOS) +COMMON = $(DEMODIR)/democom +SRC = $(DEMODIR)/src + +# FXNODES= $(DEMODIR)/../fxnodes + +ifeq ($(RWLOGO), 1) +RWLIBS += $(RWLIBDIR)/$(LP)rplogo.$(L) +CFLAGS += -DRWLOGO +endif + +ifeq ($(RWSPLASH), 1) +CFLAGS += -DRWSPLASH +endif + +CINCLUDE += \ + -I$(RWINCDIR) \ + -I$(RWSDK)/include/$(RWPLATFORM)/archive \ + -I$(COMMON) \ + -I$(SKEL) \ + -I$(SKELPS) \ + -I$(SRC) + +CFLAGS += \ + -DRWTARGET_$(RWPLATFORMEXE) \ + $(CINCLUDE) + +# -I$(FXNODES) + +include makecom/$(RWOS)/$(RWCOMPILER) + +ifeq ($(RWTEST), 1) +include ../../../tests/maketest/$(RWOS) +endif + diff --git a/maketarg b/maketarg new file mode 100644 index 0000000..1daadf9 --- /dev/null +++ b/maketarg @@ -0,0 +1,90 @@ + +OBJ += $(patsubst %.c,$(OBJDIR)/%.$(O),$(notdir $(CSRC))) +OBJ += $(patsubst %.cpp,$(OBJDIR)/%.$(O),$(notdir $(CXXSRC))) +OBJ += $(SKELOBJ) + +ifeq ("$(RWTARGET)", "xbox") +TARGET = $(XBOXPROJS) +else +TARGET = $(PROJS) +endif + +# VALIDATE will be done first, if set. +demo: $(VALIDATE) $(OBJDIR) $(TARGET) + +$(OBJDIR): + $(MD) $@ + +$(PROJS): $(OPTPROJ) $(OBJ) $(RWLIBS) + $(LD) $(SYSOBJ) $(OBJ) $(RWLIBS) $(SYSLIBS) $(LOUT)$@ $(LFLAGS) + +run: demo + $(RUN) $(PROJS) + +doscheck: + cygfind . -print | doschk + +distclean: clean $(OPTDISTCLEAN) + $(RM) *.xbe + $(RM) *.exe + $(RM) *.elf + $(RM) *.lst + $(RM) *.dsw + $(RM) *.prf + $(RM) crt0.* + $(RM) .map + $(RM) -r obj + $(RM) -r $(DEMO)_*Data + +clean: + $(RM) $(OBJ) $(OPTPROJ) + +# Rules + +$(OBJDIR)/%.$(O): $(SKEL)/%.c + $(CC) $(CFLAGS) $(COUT)$@ $< + +$(OBJDIR)/%.$(O): $(SKELPS)/%.c + $(CC) $(CFLAGS) $(COUT)$@ $< + +$(OBJDIR)/%.$(O): $(COMMON)/%.c + $(CC) $(CFLAGS) $(COUT)$@ $< + +$(OBJDIR)/%.$(O): $(SRC)/%.c + $(CC) $(CFLAGS) $(COUT)$@ $< + + +$(OBJDIR)/%.$(O): $(SRC)/$(RWOS)/%.c + $(CC) $(CFLAGS) $(COUT)$@ $< + +%.$(O) : %.c + $(CC) $(CFLAGS) $(COUT)$@ $< + +# $(OBJDIR)/%.$(O): $(FXNODES)/%.c +# $(CC) $(CFLAGS) $(COUT)$@ $< + + + + + +# c++ Rules + +$(OBJDIR)/%.$(O): $(SKEL)/%.cpp + $(CXX) $(CFLAGS) $(COUT)$@ $< + +$(OBJDIR)/%.$(O): $(SKELPS)/%.cpp + $(CXX) $(CFLAGS) $(COUT)$@ $< + +$(OBJDIR)/%.$(O): $(COMMON)/%.cpp + $(CXX) $(CFLAGS) $(COUT)$@ $< + +$(OBJDIR)/%.$(O): $(SRC)/%.cpp + $(CXX) $(CFLAGS) $(COUT)$@ $< + + +$(OBJDIR)/%.$(O): $(SRC)/$(RWOS)/%.cpp + $(CXX) $(CFLAGS) $(COUT)$@ $< + +%.$(O) : %.cpp + $(CXX) $(CFLAGS) $(COUT)$@ $< + diff --git a/models/player.dff b/models/player.dff new file mode 100755 index 0000000000000000000000000000000000000000..36409ac6f3967f2cb944ff090f708ee937bc2985 GIT binary patch literal 77824 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

N#QDd^wqx@Gi%0Oju&}0>+t#-E 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 +#include "rwcore.h" +#include "common.h" +#include "libcdvd.h" +#include "FileMgr.h" + +char CFileMgr::ms_rootDirName[128] = "\\"; +char CFileMgr::ms_dirName[128]; + +void SkySetDirectory(char *dir) {} // TODO: skyfs.c + +void +CFileMgr::Initialise(void) +{ + SkySetDirectory(ms_rootDirName); +} + +void +CFileMgr::ChangeDir(const char *dir) +{ + if(*dir == '\\'){ + strcpy(ms_dirName, ms_rootDirName); + dir++; + } + if(*dir != '\0'){ + strcat(ms_dirName, dir); + if(dir[strlen(dir)-1] != '\\') + strcat(ms_dirName, "\\"); + } + SkySetDirectory(ms_dirName); +} + +void +CFileMgr::SetDir(const char *dir) +{ + strcpy(ms_dirName, ms_rootDirName); + if(*dir != '\0'){ + strcat(ms_dirName, dir); + if(dir[strlen(dir)-1] != '\\') + strcat(ms_dirName, "\\"); + } + SkySetDirectory(ms_dirName); +} + +// actually no mode on PS2 +ssize_t +CFileMgr::LoadFile(const char *file, uint8 *buf, int maxlen, const char *mode) +{ + void *fp; + int len, size; + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + fp = fileFuncs->rwfopen(file, "r"); + if(fp == nil) + return -1; + size = 0; + // actually fwread returns size_t, so always positive... + while(len = fileFuncs->rwfread(buf+size, 1, 0x4000, fp), len >= 0){ + size += len; + if(size > maxlen) + assert(0 && "read past buffer"); + if(len != 0x4000){ + fileFuncs->rwfclose(fp); + return size; + } + } + return -1; +} + +int +CFileMgr::OpenFile(const char *file) +{ + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + return (int)fileFuncs->rwfopen(file, "r"); +} + +int +CFileMgr::OpenFileForWriting(const char *file) +{ + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + return (int)fileFuncs->rwfopen(file, "wo"); +} + +size_t +CFileMgr::Read(int fd, char *buf, ssize_t len) +{ + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + return (int)fileFuncs->rwfread(buf, 1, len, (void*)fd); +} + +size_t +CFileMgr::Write(int fd, const char *buf, ssize_t len) +{ + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + return (int)fileFuncs->rwfwrite(buf, 1, len, (void*)fd); +} + +bool +CFileMgr::Seek(int fd, int offset, int whence) +{ + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + return (int)fileFuncs->rwfseek((void*)fd, offset, whence); +} + +bool +CFileMgr::ReadLine(int fd, char *buf, int len) +{ + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + return fileFuncs->rwfgets(buf, len, (void*)fd) > 0; +} + +int +CFileMgr::CloseFile(int fd) +{ + RwFileFunctions *fileFuncs; + + fileFuncs = RwOsGetFileInterface(); + return (int)fileFuncs->rwfclose((void*)fd); +} + +bool +CFileMgr::GetCdFile(const char *file, uint32 &pos, uint32 &size) +{ + sceCdlFILE cdfile; + if(sceCdSearchFile(&cdfile, file) == 0) + return false; + pos = cdfile.lsn; + size = cdfile.size; + return true; +} + +void +CFileMgr::InitCd(void) +{ + sceCdDiskReady(0); + sceCdStandby(); + sceCdSync(0); +} + +void +CFileMgr::InitCdSystem(void) +{ + sceCdInit(SCECdINIT); + sceCdMmode(SCECdDVD); +} diff --git a/src/FileMgr.h b/src/FileMgr.h new file mode 100644 index 0000000..276a459 --- /dev/null +++ b/src/FileMgr.h @@ -0,0 +1,31 @@ +class CFileMgr +{ + static char ms_rootDirName[128]; + static char ms_dirName[128]; +public: + static void Initialise(void); + static void ChangeDir(const char *dir); + static void SetDir(const char *dir); +// not on PS2 + static void SetDirMyDocuments(void); + static ssize_t LoadFile(const char *file, uint8 *buf, int maxlen, const char *mode); +// not on PS2 + static int OpenFile(const char *file, const char *mode); + static int OpenFile(const char *file); + static int OpenFileForWriting(const char *file); + static size_t Read(int fd, char *buf, ssize_t len); + static size_t Write(int fd, const char *buf, ssize_t len); + static bool Seek(int fd, int offset, int whence); + static bool ReadLine(int fd, char *buf, int len); + static int CloseFile(int fd); +// not on PS2 + static int GetErrorReadWrite(int fd); +// not on PS2 + static char *GetRootDirName() { return ms_rootDirName; } + +// only PS2 + static bool GetCdFile(const char *file, uint32 &xx, uint32 &yy); + static void InitCd(void); + static void InitCdSystem(void); +}; + diff --git a/src/Pad.cpp b/src/Pad.cpp new file mode 100644 index 0000000..b51cd8c --- /dev/null +++ b/src/Pad.cpp @@ -0,0 +1,153 @@ +#include "common.h" +#include "rwcore.h" + +#include "eeregs.h" +#include "sifdev.h" +#include "sifrpc.h" + +#include "libpad.h" + +#include "Pad.h" + +static unsigned char ReadData[32] __attribute__ ((aligned(64))); +static u_long128 PadDmaBuffer[scePadDmaBufferMax] __attribute__ ((aligned(64))); +static u_long128 PadDmaBuffer2[scePadDmaBufferMax] __attribute__ ((aligned(64))); + +Pad pad1; + + +RwBool +PadInit(void) +{ + scePadInit(0); + scePadPortOpen(0, 0, PadDmaBuffer); + scePadPortOpen(1, 0, PadDmaBuffer2); + + return TRUE; +} + +#define Min(x, y) ((x) < (y) ? (x) : (y)) +#define Max(x, y) ((x) > (y) ? (x) : (y)) + +void +UpdatePad(Pad *pad, int port) +{ + unsigned int PadData; + int id, ext_id; + int state; + + pad->OldState = pad->NewState; + memset(&pad->NewState, 0, sizeof(pad->NewState)); + + state = scePadGetState(port, 0); + + switch(pad->Phase){ + // Detect + case 0: + // wait for stable state + if(state != scePadStateStable && state != scePadStateFindCTP1) + break; + + id = scePadInfoMode(port, 0, InfoModeCurID, 0); + if(id==0) break; + + ext_id = scePadInfoMode(port, 0, InfoModeCurExID,0); + if(ext_id>0) id = ext_id; + + switch(id) { + /* STANDARD */ + case 4: + pad->Phase = 40; + break; + + /* ANALOG */ + case 7: + pad->Phase = 70; + break; + + default: + pad->Phase = 99; + break; + } + break; + + // Standard Controller + case 40: + // check if there are modes + if (scePadInfoMode(port, 0, InfoModeIdTable, -1)==0) { + pad->Phase = 99; + break; + } + pad->Phase++; + // fall through + case 41: + // set mode to analog but don't lock + if (scePadSetMainMode(port, 0, 1, 0)==1) + pad->Phase++; + break; + case 42: + // wait until set + if (scePadGetReqState(port, 0)==scePadReqStateFaild) + pad->Phase--; + // check info again, should now be analog + if (scePadGetReqState(port, 0)==scePadReqStateComplete) + pad->Phase = 0; + break; + + // DualShock2 + case 70: + // check if we can have pressure sensitive buttons + if (scePadInfoPressMode(port,0)==1) { + pad->Phase = 76; + break; + } + pad->Phase = 99; + break; + case 76: + // yes, enable + if (scePadEnterPressMode(port, 0)==1) + pad->Phase++; + break; + case 77: + // wait until enabled + if (scePadGetReqState(port, 0)==scePadReqStateFaild) + pad->Phase--; + if (scePadGetReqState(port, 0)==scePadReqStateComplete) + pad->Phase = 99; + break; + + default: + // wait for stable state + if(state != scePadStateStable && state != scePadStateFindCTP1) + break; + + if(scePadRead(port, 0, ReadData) > 0) + PadData = 0xffff ^ ((ReadData[2] << 8) | ReadData[3]); + else + PadData = 0; + + if(PadData & SCE_PADLup) pad->NewState.DPadUp = 255; + if(PadData & SCE_PADLdown) pad->NewState.DPadDown = 255; + if(PadData & SCE_PADLleft) pad->NewState.DPadLeft = 255; + if(PadData & SCE_PADLright) pad->NewState.DPadRight = 255; + if(PadData & SCE_PADstart) pad->NewState.Start = 255; + if(PadData & SCE_PADselect) pad->NewState.Select = 255; + if(PadData & SCE_PADRup) pad->NewState.Triangle = 255; + if(PadData & SCE_PADRdown) pad->NewState.Cross = 255; + if(PadData & SCE_PADRleft) pad->NewState.Square = 255; + if(PadData & SCE_PADRright) pad->NewState.Circle = 255; + if(PadData & SCE_PADL1) pad->NewState.LeftShoulder1 = 255; + if(PadData & SCE_PADL2) pad->NewState.LeftShoulder2 = 255; + if(PadData & SCE_PADR1) pad->NewState.RightShoulder1 = 255; + if(PadData & SCE_PADR2) pad->NewState.RightShoulder2 = 255; + if(PadData & SCE_PADi) pad->NewState.LeftShock = 255; + if(PadData & SCE_PADj) pad->NewState.RightShock = 255; +#define CLAMP_AXIS(x) (((x) < 43 && (x) >= -42) ? 0 : (((x) > 0) ? (Max((x)-42, 0)*127/85) : Min((x)+42, 0)*127/85)) +#define GET_AXIS(x) CLAMP_AXIS((x)-128) + pad->NewState.RightStickX = GET_AXIS((int16)ReadData[4]); + pad->NewState.RightStickY = GET_AXIS((int16)ReadData[5]); + pad->NewState.LeftStickX = GET_AXIS((int16)ReadData[6]); + pad->NewState.LeftStickY = GET_AXIS((int16)ReadData[7]); + } +} + diff --git a/src/Pad.h b/src/Pad.h new file mode 100644 index 0000000..b856c80 --- /dev/null +++ b/src/Pad.h @@ -0,0 +1,31 @@ + +typedef struct ControllerState ControllerState; +struct ControllerState +{ + int16 LeftStickX, LeftStickY; + int16 RightStickX, RightStickY; + int16 LeftShoulder1, LeftShoulder2; + int16 RightShoulder1, RightShoulder2; + int16 DPadUp, DPadDown, DPadLeft, DPadRight; + int16 Start, Select; + int16 Square, Triangle, Cross, Circle; + int16 LeftShock, RightShock; + int16 NetworkTalk; + +// float GetLeftStickX(void) { return LeftStickX/32767.0f; }; +// float GetLeftStickY(void) { return LeftStickY/32767.0f; }; +// float GetRightStickX(void) { return RightStickX/32767.0f; }; +// float GetRightStickY(void) { return RightStickY/32767.0f; }; +}; + +typedef struct Pad Pad; +struct Pad +{ + ControllerState OldState, NewState; + int Phase; +}; +extern Pad pad1; + +RwBool SkyPadDetect(void); +RwBool PadInit(void); +void UpdatePad(Pad *pad, int port); diff --git a/src/camera.c b/src/camera.c new file mode 100644 index 0000000..aed1545 --- /dev/null +++ b/src/camera.c @@ -0,0 +1,408 @@ +#include "rwcore.h" + +#include "camera.h" + + +/* + ***************************************************************************** + */ +void +CameraSize(RwCamera *camera, RwRect *rect, RwReal viewWindow, RwReal aspectRatio) +{ + if( camera ) + { + RwVideoMode videoMode; + static RwRect origSize = {0, 0, 0, 0}; + + if( origSize.w == 0 || origSize.h == 0 ) + { + origSize.x = origSize.y = 0; + origSize.w = RwRasterGetWidth(RwCameraGetRaster(camera)); + origSize.h = RwRasterGetHeight(RwCameraGetRaster(camera)); + } + + RwEngineGetVideoModeInfo(&videoMode, RwEngineGetCurrentVideoMode()); + + if( !rect ) + { + static RwRect r; + + rect = &r; + + /* + * Rect not specified - reuse current values... + */ + rect->w = RwRasterGetWidth(RwCameraGetRaster(camera)); + rect->h = RwRasterGetHeight(RwCameraGetRaster(camera)); + rect->x = rect->y = 0; + } + + /* + * For full screen applications, resizing the camera just doesn't + * make sense, use the video mode size... + */ + if( videoMode.flags & rwVIDEOMODEEXCLUSIVE ) + { + rect->x = rect->y = 0; + rect->w = videoMode.width; + rect->h = videoMode.height; + } + + if( (rect->w > 0) && (rect->h > 0) ) + { + RwV2d vw; + RwRaster *raster = NULL; + RwRaster *zRaster = NULL; + + /* + * In OpenGl & D3D8 you don't need to care about the rasters + * of the cameras + */ +#if (defined(D3D8_DRVMODEL_H)) || (defined(OPENGL_DRVMODEL_H)) + raster = RwCameraGetRaster(camera); + zRaster = RwCameraGetZRaster(camera); + + raster->width = rect->w; + raster->height= rect->h; + + zRaster->width = rect->w; + zRaster->height= rect->h; + +#else + /* + * Destroy rasters... + */ + raster = RwCameraGetRaster(camera); + if( raster ) + { + RwRasterDestroy(raster); + + raster = NULL; + } + + zRaster = RwCameraGetZRaster(camera); + if( zRaster ) + { + RwRasterDestroy(zRaster); + + zRaster = NULL; + } + + /* + * Create new rasters... + */ + raster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA); + zRaster = RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER); + + if( raster && zRaster ) + { + RwCameraSetRaster(camera, raster); + RwCameraSetZRaster(camera, zRaster); + } + else + { + if( raster ) + { + RwRasterDestroy(raster); + + raster = NULL; + } + + if( zRaster ) + { + RwRasterDestroy(zRaster); + + zRaster = NULL; + } + + rect->w = origSize.w; + rect->h = origSize.h; + + /* + * Use default values... + */ + raster = + RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPECAMERA); + + zRaster = + RwRasterCreate(rect->w, rect->h, 0, rwRASTERTYPEZBUFFER); + + RwCameraSetRaster(camera, raster); + RwCameraSetZRaster(camera, zRaster); + + return; + } +#endif + + /* + * Figure out the view window... + */ + if( videoMode.flags & rwVIDEOMODEEXCLUSIVE ) + { + /* + * Derive ratio from aspect ratio... + */ + vw.x = viewWindow; + vw.y = viewWindow / aspectRatio; + } + else + { + + /* + * In OpenGl & D3D8 you don't need to care about the rasters + * of the cameras, just change the aspect ratio + */ +#if (defined(D3D8_DRVMODEL_H)) || (defined(OPENGL_DRVMODEL_H)) +#else + rect->w = RwRasterGetWidth(RwCameraGetRaster(camera)); + rect->h = RwRasterGetHeight(RwCameraGetRaster(camera)); +#endif + /* + * Derive from pixel ratios... + */ + if( rect->w > rect->h ) + { + vw.x = viewWindow; + vw.y = (rect->h * viewWindow) / rect->w; + } + else + { + vw.x = (rect->w * viewWindow) / rect->h; + vw.y = viewWindow; + } + } + + RwCameraSetViewWindow(camera, &vw); + } + } + + return; +} + + +/* + ***************************************************************************** + */ +void +CameraDestroy(RwCamera *camera) +{ + if( camera ) + { + RwRaster *raster; + RwFrame *frame; + + frame = RwCameraGetFrame(camera); + if( frame ) + { + RwCameraSetFrame(camera, NULL); + + RwFrameDestroy(frame); + } + + raster = RwCameraGetRaster(camera); + if( raster ) + { + RwRasterDestroy(raster); + + RwCameraSetRaster(camera, NULL); + } + + raster = RwCameraGetZRaster(camera); + if( raster ) + { + RwRasterDestroy(raster); + + RwCameraSetZRaster(camera, NULL); + } + + RwCameraDestroy(camera); + } + + return; +} + + +/* + ***************************************************************************** + */ +RwCamera * +CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer) +{ + RwCamera *camera; + + camera = RwCameraCreate(); + if( camera ) + { + RwCameraSetFrame(camera, RwFrameCreate()); + + RwCameraSetRaster(camera, + RwRasterCreate(width, height, 0, rwRASTERTYPECAMERA)); + + if( zBuffer ) + { + RwCameraSetZRaster(camera, + RwRasterCreate(width, height, 0, rwRASTERTYPEZBUFFER)); + } + + /* + * Check everything is valid... + */ + if( RwCameraGetFrame(camera) && RwCameraGetRaster(camera) && + (!zBuffer || RwCameraGetZRaster(camera)) ) + { + /* + * Everything OK... + */ + return camera; + } + } + + /* + * Error - so clean up... + */ + CameraDestroy(camera); + + return NULL; +} + + +/* + ***************************************************************************** + */ +void +CameraMove(RwCamera *camera, RwV3d *delta) +{ + RwV3d offset; + RwFrame *cameraFrame; + RwMatrix *cameraMatrix; + RwV3d *at, *up, *right; + + cameraFrame = RwCameraGetFrame(camera); + cameraMatrix = RwFrameGetMatrix(cameraFrame); + + at = RwMatrixGetAt(cameraMatrix); + up = RwMatrixGetUp(cameraMatrix); + right = RwMatrixGetRight(cameraMatrix); + + offset.x = delta->x * right->x + delta->y * up->x + delta->z * at->x; + offset.y = delta->x * right->y + delta->y * up->y + delta->z * at->y; + offset.z = delta->x * right->z + delta->y * up->z + delta->z * at->z; + + RwFrameTranslate(cameraFrame, &offset, rwCOMBINEPOSTCONCAT); + + return; +} + + +/* + ***************************************************************************** + */ +void +CameraPan(RwCamera *camera, const RwV3d *pos, RwReal angle) +{ + RwV3d invCamPos; + RwFrame *cameraFrame; + RwMatrix *cameraMatrix; + RwV3d camPos; + + cameraFrame = RwCameraGetFrame(camera); + cameraMatrix = RwFrameGetMatrix(cameraFrame); + + camPos = (pos) ? *pos : *RwMatrixGetPos(cameraMatrix); + + RwV3dScale(&invCamPos, &camPos, -1.0f); + + /* + * Translate the camera back to the rotation origin... + */ + RwFrameTranslate(cameraFrame, &invCamPos, rwCOMBINEPOSTCONCAT); + + /* + * Get the camera's UP vector and use this as the axis of rotation... + */ + RwMatrixRotate(cameraMatrix, + RwMatrixGetUp(cameraMatrix), angle, rwCOMBINEPOSTCONCAT); + + /* + * Translate the camera back to its original position... + */ + RwFrameTranslate(cameraFrame, &camPos, rwCOMBINEPOSTCONCAT); + + return; +} + + +/* + ***************************************************************************** + */ +void +CameraTilt(RwCamera *camera, const RwV3d *pos, RwReal angle) +{ + RwV3d invCamPos; + RwFrame *cameraFrame; + RwMatrix *cameraMatrix; + RwV3d camPos; + + cameraFrame = RwCameraGetFrame(camera); + cameraMatrix = RwFrameGetMatrix(cameraFrame); + + camPos = (pos) ? *pos : *RwMatrixGetPos(cameraMatrix); + + RwV3dScale(&invCamPos, &camPos, -1.0f); + + /* + * Translate the camera back to the rotation origin... + */ + RwFrameTranslate(cameraFrame, &invCamPos, rwCOMBINEPOSTCONCAT); + + /* + * Get the camera's RIGHT vector and use this as the axis of rotation... + */ + RwMatrixRotate(cameraMatrix, + RwMatrixGetRight(cameraMatrix), angle, rwCOMBINEPOSTCONCAT); + + /* + * Translate the camera back to its original position... + */ + RwFrameTranslate(cameraFrame, &camPos, rwCOMBINEPOSTCONCAT); + + return; +} + + +/* + ***************************************************************************** + */ +void +CameraRotate(RwCamera *camera, const RwV3d *pos, RwReal angle) +{ + RwV3d invCamPos; + RwFrame *cameraFrame; + RwMatrix *cameraMatrix; + RwV3d camPos; + + cameraFrame = RwCameraGetFrame(camera); + cameraMatrix = RwFrameGetMatrix(cameraFrame); + + camPos = (pos) ? *pos : *RwMatrixGetPos(cameraMatrix); + + RwV3dScale(&invCamPos, &camPos, -1.0f); + + /* + * Translate the camera back to the rotation origin... + */ + RwFrameTranslate(cameraFrame, &invCamPos, rwCOMBINEPOSTCONCAT); + + /* + * Get the camera's AT vector and use this as the axis of rotation... + */ + RwMatrixRotate(cameraMatrix, RwMatrixGetAt(cameraMatrix), + angle, rwCOMBINEPOSTCONCAT); + + /* + * Translate the camera back to its original position... + */ + RwFrameTranslate(cameraFrame, &camPos, rwCOMBINEPOSTCONCAT); + + return; +} diff --git a/src/camera.h b/src/camera.h new file mode 100644 index 0000000..787b12d --- /dev/null +++ b/src/camera.h @@ -0,0 +1,60 @@ + +/**************************************************************************** + * + * camera.h + * + * This file is a product of Criterion Software Ltd. + * + * This file is provided as is with no warranties of any kind and is + * provided without any obligation on Criterion Software Ltd. + * or Canon Inc. to assist in its use or modification. + * + * Criterion Software Ltd. and Canon Inc. will not, under any + * circumstances, be liable for any lost revenue or other damages + * arising from the use of this file. + * + * Copyright (c) 1999, 2000 Criterion Software Ltd. + * All Rights Reserved. + * + */ + +#if (!defined(_CAMERA_H)) +#define _CAMERA_H + +#include "rwcore.h" + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +extern void +CameraMove(RwCamera *camera, RwV3d *offset); + +extern void +CameraTilt(RwCamera *camera, const RwV3d *pos, RwReal angle); + +extern void +CameraPan(RwCamera *camera, const RwV3d *pos, RwReal angle); + +extern void +CameraRotate(RwCamera *camera, const RwV3d *pos, RwReal angle); + +extern void +CameraSize(RwCamera *camera, RwRect *rect, RwReal viewWindow, RwReal aspectRatio); + +extern void +CameraDestroy(RwCamera *camera); + +extern RwCamera * +CameraCreate(RwInt32 width, RwInt32 height, RwBool zBuffer); + +extern RwRaster * +CameraCreateCrossHair(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* (!defined(_CAMERA_H)) */ + diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..eab22d9 --- /dev/null +++ b/src/common.h @@ -0,0 +1,11 @@ + +typedef unsigned char uint8; +typedef signed char int8; +typedef unsigned short uint16; +typedef signed short int16; +typedef unsigned int uint32; +typedef signed int int32; +//typedef int32 ssize_t; +//typedef uint32 size_t; + +#define nil NULL diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..44452ab --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,884 @@ +//////////// NB: for non-devkits all these have to be defined!!! +// this disconnects dsedb if run with -r run foo.elf +// but it works if you run from within dsedb +//#define REBOOT_IOP +//#define IOP_CDROM // load IOP modules from CD +#define CDROM // enable CD support + + +#include +#include "rwcore.h" +#include "rpworld.h" + +#ifdef RWMETRICS +#include "metrics.h" +#endif + +#include "rtcharse.h" + +#if (!defined(RWDEBUG)) +#define __RWRELEASEUNUSED__ __RWUNUSED__ +#endif /* (!defined(RWDEBUG)) */ + +#if (!defined(__RWRELEASEUNUSED__)) +#define __RWRELEASEUNUSED__ /* No op */ +#endif /* (!defined(__RWRELEASEUNUSED__)) */ + +#if (!defined(__GNUC__)) +#define __FUNCTION__ "Unknown" +#endif /* (!defined(__GNUC__)) */ + + +// skeleton stuff +#include "camera.h" +#include "skyfs.h" + +// SCE stuff +#include "eeregs.h" +#include "sifdev.h" +#include "sifrpc.h" +#include "libpad.h" +#ifdef CDROM +#include "libcdvd.h" +#endif + + +#include "common.h" +#include "FileMgr.h" +#include "Pad.h" + +#ifdef WIDE_SCREEN +#define DEFAULT_ASPECTRATIO (16.0f/9.0f) +#else +#define DEFAULT_ASPECTRATIO (4.0f/3.0f) +#endif + +#define DEFAULT_VIEWWINDOW (0.5f) + +static RwInt32 FrameCounter = 0; +static RwInt32 FramesPerSecond = 0; + +static RwRGBA ForegroundColor = {200, 200, 200, 255}; +static RwRGBA BackgroundColor = { 64, 64, 64, 0}; + +static RtCharset *Charset = NULL; +static RpLight *AmbientLight = NULL; +static RpLight *MainLight = NULL; + +RpClump *Clump = NULL; +RpWorld *World = NULL; +RwCamera *Camera = NULL; +RwTexDictionary *TexDict = NULL; + + + +void RsTerminate(void); +RwBool RsInitialise(void); +void RsRwTerminate(void); +RwBool RsRwInitialise(void); + +RwUInt32 RsTimer(void); +void RsErrorMessage(const RwChar * message); + +typedef struct RsGlobalType RsGlobalType; +struct RsGlobalType +{ + const RwChar *appName; + RwInt32 maximumWidth; + RwInt32 maximumHeight; + RwInt32 maxFPS; + RwBool quit; + + void *ps; /* platform specific data */ +}; +RsGlobalType RsGlobal; + + + +struct DirEntry +{ + uint32 offset; + uint32 size; + char name[24]; +}; +DirEntry directory[4000]; +uint32 maxFileSize; +uint8 *streamBuffer; + +int cdImageFD; + +void +LoadDirectory(int fd) +{ + DirEntry de; + int i = 0; + while(CFileMgr::Read(fd, (char*)&de, 32) == 32){ +// printf("dir: %08X %08X %s\n", de.offset, de.size, de.name); + directory[i++] = de; + if(de.size > maxFileSize) + maxFileSize = de.size; + } +} +int +FindDirEntry(const char *name) +{ + int i; + for(i = 0; i < 4000; i++){ + if(directory[i].offset == 0 && + directory[i].size == 0) + return -1; + if(strcasecmp(directory[i].name, name) == 0) + return i; + } + return -1; +} + + +static RpWorld * +CreateWorld(void) +{ + RpWorld *world; + RwBBox bBox; + + bBox.sup.x = bBox.sup.y = bBox.sup.z = 100.0f; + bBox.inf.x = bBox.inf.y = bBox.inf.z = -100.0f; + + world = RpWorldCreate(&bBox); + + return world; +} + + +static RpLight * +CreateAmbientLight(RpWorld *world) +{ + RpLight *light; + + light = RpLightCreate(rpLIGHTAMBIENT); + if(light) { + RwRGBAReal color; + + color.red = color.green = color.blue = 0.3f; + color.alpha = 1.0f; + + RpLightSetColor(light, &color); + RpWorldAddLight(world, light); + + return light; + } + + return NULL; +} + + +static RpLight * +CreateMainLight(RpWorld *world) +{ + RpLight *light; + + light = RpLightCreate(rpLIGHTDIRECTIONAL); + if(light) { + RwFrame *frame; + + frame = RwFrameCreate(); + if(frame) { + RwV3d xAxis = {1.0f, 0.0f, 0.0f}; + RwV3d yAxis = {0.0f, 1.0f, 0.0f}; + + RwFrameRotate(frame, &xAxis, 30.0f, rwCOMBINEREPLACE); + RwFrameRotate(frame, &yAxis, 30.0f, rwCOMBINEPOSTCONCAT); + + RpLightSetFrame(light, frame); + + RpWorldAddLight(world, light); + + return light; + } + + RpLightDestroy(light); + } + + return NULL; +} + + +static RwCamera * +CreateCamera(RpWorld *world) +{ + RwCamera *camera; + + camera = CameraCreate(RsGlobal.maximumWidth, RsGlobal.maximumHeight, TRUE); + if(camera) { + RwFrame *frame; + RwV3d pos; + + frame = RwCameraGetFrame(camera); + + pos = *RwMatrixGetAt(RwFrameGetMatrix(frame)); + RwV3dScale(&pos, &pos, -5.0f); + + RwFrameTranslate(frame, &pos, rwCOMBINEREPLACE); + + RwCameraSetFarClipPlane(camera, 250.0f); + RwCameraSetNearClipPlane(camera, 0.5f); + + RpWorldAddCamera(world, camera); + + return camera; + } + + return NULL; +} + +RwStream* +OpenFromDirectory(const char *name) +{ + int slot; + RwMemory mem; + + slot = FindDirEntry(name); + if(slot == -1){ + printf("couldn't find <%s>\n", name); + return NULL; + } + printf("found <%s>: %d %X %X\n", name, slot, directory[slot].offset, directory[slot].size); + CFileMgr::Seek(cdImageFD, directory[slot].offset*2048, 0); + CFileMgr::Read(cdImageFD, (char*)streamBuffer, directory[slot].size*2048); + mem.start = streamBuffer; + mem.length = directory[slot].size*2048; + return RwStreamOpen(rwSTREAMMEMORY, rwSTREAMREAD, &mem); +} + +#define USE_CDIMAGE +#ifdef USE_CDIMAGE +RwStream* +OpenStream(const char *name) +{ + return OpenFromDirectory(name); +} +#else +RwStream* +OpenStream(const char *name) +{ + char path[256]; + sprintf(path, "./models/%s", name); + return RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, path); +} +#endif + +static RpClump * +LoadClump(const RwChar *file) +{ + RpClump *clump = NULL; + RwStream *stream; + + stream = OpenStream(file); + if(stream) { + if(RwStreamFindChunk(stream, rwID_CLUMP, NULL, NULL)) + clump = RpClumpStreamRead(stream); + + RwStreamClose(stream, NULL); + } + + return clump; +} + + +static RpClump * +CreateClump(RpWorld *world) +{ + RpClump *clump; + + clump = LoadClump("player.dff"); + if( clump == NULL ) + return NULL; + + RpWorldAddClump(world, clump); + + return clump; +} + +static RwTexDictionary* +LoadTextureDictionary(const char *file) +{ + RwTexDictionary *texDict = NULL; + RwStream *stream; + + stream = OpenStream(file); + if(stream) { + if(RwStreamFindChunk(stream, rwID_TEXDICTIONARY, NULL, NULL)) + texDict = RwTexDictionaryStreamRead(stream); + + RwStreamClose(stream, NULL); + } + + return texDict; +}; + +static RwBool +Initialise(void) +{ + if(RsInitialise()) { + RsGlobal.appName = "GTA test"; + RsGlobal.maxFPS = 120; + + return TRUE; + } + + return FALSE; +} + + +uint8 buf[24*1024]; + +void +InitDirectory(void) +{ + int fd; + + fd = CFileMgr::OpenFile("cdrom0:\\MODELS\\GTA3.DIR"); + if(fd == 0){ + printf("error opening\n"); + return; + } + LoadDirectory(fd); + CFileMgr::CloseFile(fd); + streamBuffer = (uint8*)RwMalloc(maxFileSize*2048); + + cdImageFD = CFileMgr::OpenFile("cdrom0:\\MODELS\\GTA3.IMG"); + if(cdImageFD == 0){ + printf("error opening\n"); + return; + } +} + +RwBool +Initialise3D(void) +{ + if(!RsRwInitialise()) { + RsErrorMessage("Error initializing RenderWare."); + return FALSE; + } + + InitDirectory(); + + Charset = RtCharsetCreate(&ForegroundColor, &BackgroundColor); + if(Charset == NULL) { + RsErrorMessage("Cannot create raster charset."); + return FALSE; + } + + World = CreateWorld(); + if(World == NULL) { + RsErrorMessage("Cannot create world."); + return FALSE; + } + + AmbientLight = CreateAmbientLight(World); + if(AmbientLight == NULL) { + RsErrorMessage("Cannot create ambient light."); + return FALSE; + } + + MainLight = CreateMainLight(World); + if(MainLight == NULL) { + RsErrorMessage("Cannot create main light."); + return FALSE; + } + + Camera = CreateCamera(World); + if(Camera == NULL) { + RsErrorMessage("Cannot create camera."); + return FALSE; + } + + TexDict = LoadTextureDictionary("player.txd"); + if(TexDict) + RwTexDictionarySetCurrent(TexDict); + + Clump = CreateClump(World); + if(Clump == NULL) { + RsErrorMessage("Cannot create clump."); + return FALSE; + } + +#ifdef RWMETRICS + RsMetricsOpen(Camera); +#endif + + return TRUE; +} + + +static void +Terminate3D(void) +{ +#ifdef RWMETRICS + RsMetricsClose(); +#endif + + if(Clump) { + RpWorldRemoveClump(World, Clump); + RpClumpDestroy(Clump); + } + + if(Camera) { + RpWorldRemoveCamera(World, Camera); + + CameraDestroy(Camera); + } + + if(AmbientLight) { + RpWorldRemoveLight(World, AmbientLight); + + RpLightDestroy(AmbientLight); + } + + if(MainLight) { + RwFrame *frame; + + RpWorldRemoveLight(World, MainLight); + + frame = RpLightGetFrame(MainLight); + RpLightSetFrame(MainLight, NULL); + RwFrameDestroy(frame); + + RpLightDestroy(MainLight); + } + + if(World) + RpWorldDestroy(World); + + if(Charset) + RwRasterDestroy(Charset); + + RsRwTerminate(); +} + + +static RwBool +AttachPlugins(void) +{ + if(!RpWorldPluginAttach()) + return FALSE; + return TRUE; +} + +void +FrameRotate(RwReal xAngle, RwReal yAngle) +{ + RwFrame *frame; + RwV3d *right, *up; + RwV3d pos; + + frame = RpClumpGetFrame(Clump); + + right = RwMatrixGetRight(RwFrameGetMatrix(RwCameraGetFrame(Camera))); + up = RwMatrixGetUp(RwFrameGetMatrix(RwCameraGetFrame(Camera))); + + pos = *RwMatrixGetPos(RwFrameGetMatrix(frame)); + + RwV3dScale(&pos, &pos, -1.0f); + RwFrameTranslate(frame, &pos, rwCOMBINEPOSTCONCAT); + + RwFrameRotate(frame, up, xAngle, rwCOMBINEPOSTCONCAT); + RwFrameRotate(frame, right, yAngle, rwCOMBINEPOSTCONCAT); + + RwV3dScale(&pos, &pos, -1.0f); + RwFrameTranslate(frame, &pos, rwCOMBINEPOSTCONCAT); +} + +static void +Render(void) +{ + RwCameraClear(Camera, &BackgroundColor, rwCAMERACLEARZ|rwCAMERACLEARIMAGE); + + if(RwCameraBeginUpdate(Camera)) { + RpWorldRender(World); + +#ifdef RWMETRICS + RsMetricsRender(); +#endif + + RwCameraEndUpdate(Camera); + } + + RwCameraShowRaster(Camera, NULL, 0); + + FrameCounter++; +} + + +static void +Idle(void) +{ + RwUInt32 thisTime; + + static RwBool firstCall = TRUE; + static RwUInt32 lastFrameTime; + + if(firstCall) { + lastFrameTime = RsTimer(); + firstCall = FALSE; + } + + thisTime = RsTimer(); + + if(thisTime > (lastFrameTime + 1000)) { + FramesPerSecond = FrameCounter; + FrameCounter = 0; + lastFrameTime = thisTime; + } + + + float rotx = (pad1.NewState.DPadRight - pad1.NewState.DPadLeft)/255.0f; + float roty = (pad1.NewState.DPadUp - pad1.NewState.DPadDown)/255.0f; + FrameRotate(rotx*2.0f, roty*2.0f); + + rotx = pad1.NewState.LeftStickX/128.0f; + roty = pad1.NewState.LeftStickY/128.0f; + FrameRotate(rotx*2.0f, roty*2.0f); + + Render(); +} + + + + + +volatile unsigned long sweHighCount; +int skyTimerHandlerHid; + + +static int +TimerHandler(int ca) +{ + if ((ca == INTC_TIM0) && (*T0_MODE & 0x800)) { + *T0_MODE |= 0x800; + + sweHighCount += 0x10000; + } + + ExitHandler(); + + return 0; +} + +void +RsErrorMessage(const RwChar * message __RWRELEASEUNUSED__) +{ + RwDebugSendMessage(rwDEBUGERROR, __FUNCTION__, message); +} + +void +RsWarningMessage(const RwChar * message __RWRELEASEUNUSED__) +{ + RwDebugSendMessage(rwDEBUGMESSAGE, __FUNCTION__, message); +} + +void +psDebugMessageHandler(RwDebugType type, const RwChar * str) +{ + switch (type) { +#if (defined(COLOR)) + case rwDEBUGASSERT: /* red */ + printf("\033[31m%s\033[0m\n", str); + break; + case rwDEBUGERROR: /* bold red */ + printf("\033[31;1m%s\033[0m\n", str); + break; + case rwDEBUGMESSAGE: /* blue */ + printf("\033[34m%s\033[0m\n", str); + break; +#endif + default: + printf("%s\n", str); + } +} + +RwUInt32 +RsTimer(void) +{ + unsigned long high0, low0, high1, low1; + + high0 = sweHighCount; + low0 = *T0_COUNT; + high1 = sweHighCount; + low1 = *T0_COUNT; + + if (high0 == high1) + return ((RwUInt32) ((high0 | (low0 & 0xffff)) / 9216)); + else + return ((RwUInt32) ((high1 | (low1 & 0xffff)) / 9216)); +} + +RwUInt64 +psMicroTimer(void) +{ + unsigned long high0, low0, high1, low1; + + high0 = sweHighCount; + low0 = *T0_COUNT; + high1 = sweHighCount; + low1 = *T0_COUNT; + + if (high0 == high1) + return (((RwUInt64) (high0 | (low0 & 0xffff))) * 1000) / 9216; + else + return (((RwUInt64) (high1 | (low1 & 0xffff))) * 1000) / 9216; +} + + +RwBool +RsSelectDevice(void) +{ + RwVideoMode vmodeInfo; + RwInt32 numVideoModes; + RwInt32 i; + RwVideoMode videoMode; + + numVideoModes = RwEngineGetNumVideoModes() + 1; + + for (i = 1; i < numVideoModes; i++) + if (RwEngineGetVideoModeInfo(&vmodeInfo, (i - 1))) { + if(vmodeInfo.width == 640 && vmodeInfo.height == 512 && + vmodeInfo.depth == 32 && + vmodeInfo.flags == (rwVIDEOMODEEXCLUSIVE|rwVIDEOMODEINTERLACE|rwVIDEOMODEFSAA1)) { + RwEngineSetVideoMode(i-1); + break; + } + } + RwEngineGetVideoModeInfo(&videoMode, RwEngineGetCurrentVideoMode()); + + RsGlobal.maximumWidth = videoMode.width; + RsGlobal.maximumHeight = videoMode.height; + + return TRUE; +} + +void +RsTerminate(void) +{ +} + +RwBool +RsInitialise(void) +{ + RwBool result; + + RsGlobal.appName = "RenderWare Application"; + RsGlobal.maximumWidth = 0; + RsGlobal.maximumHeight = 0; + RsGlobal.maxFPS = 0; + RsGlobal.quit = FALSE; + + return TRUE; +} + +// this is where the magic happens +char* +GetModulePath(const char *module) +{ + char tmp[64]; + static char path[256]; + char *s; + + strcpy(tmp, module); +#ifdef IOP_CDROM + strcpy(path, "cdrom0:\\SYSTEM\\"); +#else +#define TOSTRING__(arg) #arg +#define TOSTRING(arg) TOSTRING__(arg) + for(s = tmp; *s; s++) + if(isupper(*s)) *s = tolower(*s); + sprintf(path, "host0:%s/modules/", TOSTRING(IOPPATH)); +#endif + strcat(path, tmp); + return path; +} + +void +LoadModule(const char *module) +{ + static char noargs[] = ""; + char *path; + path = GetModulePath(module); + printf("Loading %s\n", path); + while(sceSifLoadModule(path, 0, noargs) < 0) + printf("Can't Load Module %s\n", path); +} + +void +TheGame(void) +{ + while (!RsGlobal.quit) { + static RwUInt32 lastpoll = 0; + RwUInt32 polltime; + + polltime = RsTimer(); + if (polltime - lastpoll > 15) { + UpdatePad(&pad1, 0); + + lastpoll = polltime; + } + + Idle(); + } +} + +void +SystemInit(void) +{ + /* by default don't look in subdirs for assets */ + skyTimerHandlerHid = -1; + + sceSifInitRpc(0); + sceSifInitIopHeap(); + +#ifdef CDROM + CFileMgr::InitCdSystem(); +#endif + +#ifdef REBOOT_IOP + printf("rebooting IOP\n"); + while(!sceSifRebootIop(GetModulePath(IOP_IMAGE_FILE))) + continue; + + while(!sceSifSyncIop()) + continue; + + sceSifInitRpc(0); + +#ifdef CDROM + CFileMgr::InitCdSystem(); +#endif + sceFsReset(); +#endif + + LoadModule("SIO2MAN.IRX"); + LoadModule("PADMAN.IRX"); + + skyTimerHandlerHid = AddIntcHandler(INTC_TIM0, TimerHandler, 0); + /* Set up time0 */ + sweHighCount = 0; + *T0_COUNT = 0; + *T0_COMP = 0; + *T0_HOLD = 0; + *T0_MODE = 0x281; + EnableIntc(INTC_TIM0); +} + +void +GameInit(void) +{ + RwRect r; + + Initialise3D(); + + r.x = 0; + r.y = 0; + r.w = RsGlobal.maximumWidth; + r.h = RsGlobal.maximumHeight; + CameraSize(Camera, &r, DEFAULT_VIEWWINDOW, DEFAULT_ASPECTRATIO); +} + +int +main(int argc, char *argv[]) +{ + SystemInit(); + + Initialise(); // not in GTA + + PadInit(); + + GameInit(); + + TheGame(); + + Terminate3D(); + RsTerminate(); + + DisableIntc(INTC_TIM0); + RemoveIntcHandler(INTC_TIM0, skyTimerHandlerHid); + + return 0; +} + + +#ifdef RWDEBUG +static RwBool +RsSetDebug(void) +{ + RwDebugSetHandler(psDebugMessageHandler); + + RwDebugSendMessage(rwDEBUGMESSAGE, RsGlobal.appName, + "Debugging Initialized"); + + return TRUE; +} +#endif + +static RwTexDictionary * +texDictDestroyCB(RwTexDictionary *dict, void *data __RWUNUSED__) +{ + RwTexDictionaryDestroy(dict); + return dict; +} + +void +RsRwTerminate(void) +{ + RtCharsetClose(); + + RwTexDictionaryForAllTexDictionaries(texDictDestroyCB, NULL); + + RwEngineStop(); + RwEngineClose(); + RwEngineTerm(); + + return; +} + +RwBool +RsRwInitialise(void) +{ + RwEngineOpenParams openParams; + + if (!RwEngineInit(NULL, 0)) + return (FALSE); + + SkyInstallFileSystem(); + +#ifdef RWDEBUG + RsSetDebug(); +#endif + + if(!AttachPlugins()) { + printf("Couldn't load the plugins for some reason\n"); + for(;;); + } + + openParams.displayID = NULL; + if (!RwEngineOpen(&openParams)) { + RwEngineTerm(); + return (FALSE); + } + + RsSelectDevice(); + + if (!RwEngineStart()) { + RwEngineClose(); + RwEngineTerm(); + return (FALSE); + } + + if (!RtCharsetOpen()) { + RwEngineStop(); + RwEngineClose(); + RwEngineTerm(); + return (FALSE); + } + + return TRUE; +} + diff --git a/src/skyfs.c b/src/skyfs.c new file mode 100644 index 0000000..802eb43 --- /dev/null +++ b/src/skyfs.c @@ -0,0 +1,738 @@ + +/**************************************************************************** + * + * skyfs.c + * + * This file is a product of Criterion Software Ltd. + * + * This file is provided as is with no warranties of any kind and is + * provided without any obligation on Criterion Software Ltd. + * or Canon Inc. to assist in its use or modification. + * + * Criterion Software Ltd. and Canon Inc. will not, under any + * circumstances, be liable for any lost revenue or other damages + * arising from the use of this file. + * + * Copyright (c) 1999, 2000 Criterion Software Ltd. + * All Rights Reserved. + * + */ + +#include "stdio.h" +#include "string.h" +#include "assert.h" + +/*#include "unistd.h"*/ +#include "sifdev.h" + +#include "rwcore.h" +#include "skyfs.h" + +/* Because CDROM is used in sky.c + * it's better to define this for a project and not here. + */ + +/* Use this define to get DEBUGSTATION behavior */ +/*#define DEBUGSTATION*/ +/* Use this define to get CDROM behavior */ +//#define CDROM + +#define READBUFFERSIZE 10240 + +#define RWGDFSGLOBAL(var) \ + (RWPLUGINOFFSET(gdfsGlobals, \ + RwEngineInstance, \ + gdfsModuleInfo.globalsOffset)->var) + +#define rwID_SKYDEVICEMODULE (MAKECHUNKID(rwVENDORID_CRITERIONINT, 0x30)) + +typedef struct skyFile skyFile; +struct skyFile +{ + int gdfs; + RwInt32 POS; + RwInt32 SOF; + RwUInt8 readBuffer[READBUFFERSIZE]; + RwUInt32 bufferPos; + RwBool bufferValid; +}; + +typedef struct gdfsGlobals gdfsGlobals; +struct gdfsGlobals +{ + RwFileFunctions oldFS; /* Old Filing system vectors */ + RwFreeList *fpFreeList; /* File pointer free list */ +}; + +/* These are all global to all RenderWare instances */ + +RwInt32 gdfsOpenFiles; +RwModuleInfo gdfsModuleInfo; + +#ifdef DEBUGSTATION +extern char debugStationFilePrefix[32]; +#endif + +/**************************************************************************** + skyTransMode + + Attempt to convert a mode string to an open mode + + On entry : access mode + On exit : integer mode + */ +static int +skyTransMode(const RwChar * access) +{ + int mode; + char *r; + char *w; + char *a; + char *plus; + char *n; + char *d; + + /* I add a couple of new characters for now: + * n non-blocking mode + * d no write back d cache */ + + r = strrchr(access, (int) 'r'); + w = strrchr(access, (int) 'w'); + a = strrchr(access, (int) 'a'); + plus = strrchr(access, (int) '+'); + n = strrchr(access, (int) 'n'); + d = strrchr(access, (int) 'd'); + + if (plus) + mode = SCE_RDWR; + else if (r) + mode = SCE_RDONLY; + else if (w) + mode = SCE_WRONLY; + else if (a) + mode = SCE_WRONLY; + else + return (0); + + /* later we will test for SCE_CREAT & !SCE_TRUNC as a seek to end of file */ + if (w) + mode |= SCE_CREAT | SCE_TRUNC; + + if (a) + mode |= SCE_CREAT; + + if (n) + mode |= SCE_NOWAIT; + + if (d) + mode |= SCE_NOWBDC; + + return (mode); +} + +/**************************************************************************** + trySkyFopen + + One attempt at opening a file + + On entry : Filename, access mode + On exit : + */ + +static void * +trySkyFopen(const RwChar * fname, const RwChar * access) +{ + skyFile *fp; + int mode; + RwChar name[256]; + RwChar *nameptr; + int cdrom = 0; + + /* First manipulate the filename into a Sky friendly name */ + if (strchr(fname, ':')) + { + strncpy(name, fname, 255); + if(strncmp(name, "cdrom", 5) == 0) + cdrom = 1; + } + else + { +#if (defined(CDROM)) + sprintf(name, "cdrom0:\\%s", fname); + cdrom = 1; + + /* append a ;1 to the end if required */ + name[253] = 0; + /* we assume that any ';' indicates a version appended */ + if (!strrchr(name, ';')) + { + strcat(name, ";1"); + } + strupr(&name[7]); +#elif (defined(DEBUGSTATION)) + strcpy(name, debugStationFilePrefix); + strcat((RwChar *)name, fname); +#else + strcpy(name, "host:"); + strcat((RwChar *)name, fname); + +#endif /* CDROM */ + } + /* force null termination */ + name[255] = 0; + + nameptr = name; + while (*nameptr) + { + if(cdrom){ + if (*nameptr == '/') + *nameptr = '\\'; + }else{ + if (*nameptr == '\\') + *nameptr = '/'; + } + nameptr++; + } + + /* Allocate structure for holding info */ + fp = (skyFile *) RwFreeListAlloc(RWGDFSGLOBAL(fpFreeList)); + if (!fp) + { + return (NULL); + } + + mode = skyTransMode(access); + if (!mode) + { + return (NULL); + } + + fp->gdfs = sceOpen(name, mode); +printf("open <%s> -> %d\n", name, fp->gdfs); + + if (fp->gdfs < 0) + { + RwFreeListFree(RWGDFSGLOBAL(fpFreeList), fp); + return (NULL); + } + + /* We seek to the end of the file to get size */ + fp->SOF = fp->POS = sceLseek(fp->gdfs, 0, SCE_SEEK_END); + if (fp->SOF < 0) + { + sceClose(fp->gdfs); + RwFreeListFree(RWGDFSGLOBAL(fpFreeList), fp); + return (NULL); + } + /* SCE_CREAT & !SCE_TRUNC mean seek to end of file */ + if (!((mode & SCE_CREAT) && !(mode & SCE_TRUNC))) + { + fp->POS = sceLseek(fp->gdfs, 0, SCE_SEEK_SET); + + if (fp->POS < 0) + { + sceClose(fp->gdfs); + RwFreeListFree(RWGDFSGLOBAL(fpFreeList), fp); + return (NULL); + } + } + + /* Initialise the buffer to show nothing buffered */ + fp->bufferPos = READBUFFERSIZE; + + gdfsOpenFiles++; + + return ((void *) fp); +} + +/**************************************************************************** + skyFopen + + On entry : Filename, access mode + On exit : + */ + +static void * +skyFopen(const RwChar * name, const RwChar * access) +{ + void *res; + + res = trySkyFopen(name, access); + + if (res) + { + return (res); + } + + return (NULL); +} + +/**************************************************************************** + skyFclose + + On entry : FILE * (data block specific to this implementation) + On exit : 0 on success + */ + +static int +skyFclose(void *fptr) +{ + skyFile *fp = (skyFile *) fptr; + + assert(fptr); + + if (fp && gdfsOpenFiles) + { + sceClose(fp->gdfs); + + RwFreeListFree(RWGDFSGLOBAL(fpFreeList), fp); + + --gdfsOpenFiles; + + return (0); + } + + return (-1); +} + +/**************************************************************************** + skyFexist + + On entry : Filename + On exit : + */ + +static RwBool +skyFexist(const RwChar * name) +{ + void *res; + + res = RwOsGetFileInterface()->rwfopen(name, "r"); + if (res) + { + RwOsGetFileInterface()->rwfclose(res); + return (TRUE); + } + + return (FALSE); +} + +/**************************************************************************** + skyFread + + On entry : Address to read to, block size, block count, file to read from + On exit : Number of bytes read + */ + +static size_t +skyFread(void *addr, size_t size, size_t count, void *fptr) +{ + skyFile *fp = (skyFile *) fptr; + size_t numBytesToRead = size * count; + int bytesRead, bytesRead2; + + bytesRead = 0; + + /* Trim number of bytes for the size of the file */ + if ((fp->POS + (RwInt32) numBytesToRead) > fp->SOF) + { + numBytesToRead = fp->SOF - fp->POS; + } + + /* First try and use the buffer */ + if ((fp->bufferPos < READBUFFERSIZE) && + (bytesRead < (RwInt32) numBytesToRead)) + { + /* Pull from the buffer */ + if (numBytesToRead < (READBUFFERSIZE - fp->bufferPos)) + { + /* Can satisfy entirely from buffer */ + bytesRead = numBytesToRead; + } + else + { + /* Pull as much as possible from the buffer */ + bytesRead = READBUFFERSIZE - fp->bufferPos; + } + + /* Copy it */ + memcpy(addr, &fp->readBuffer[fp->bufferPos], bytesRead); + + /* Update target address and source address */ + addr = (void *) ((RwUInt8 *) addr + bytesRead); + fp->bufferPos += bytesRead; + fp->POS += bytesRead; + } + + /* If next bit is bigger than a buffer, read it directly and ignore the + * buffer. + */ + if ((numBytesToRead - bytesRead) > 0) + { + if ((numBytesToRead - bytesRead) >= READBUFFERSIZE) + { + bytesRead2 = (numBytesToRead - bytesRead); + bytesRead2 = sceRead(fp->gdfs, addr, bytesRead2); + if (bytesRead2 < 0) + { + bytesRead2 = 0; + } + } + else + { + /* Go via the buffer */ + sceRead(fp->gdfs, fp->readBuffer, READBUFFERSIZE); + bytesRead2 = (numBytesToRead - bytesRead); + memcpy(addr, fp->readBuffer, bytesRead2); + fp->bufferPos = bytesRead2; + } + fp->POS += bytesRead2; + bytesRead += bytesRead2; + } + + return (bytesRead / size); +} + +/**************************************************************************** + skyFwrite + + On entry : Address to write from, block size, block count, file to write to + On exit : Number of bytes written + */ + +static size_t +skyFwrite(const void *addr, size_t size, size_t count, void *fptr) +{ + int bytesWritten; + skyFile *fp = (skyFile *) fptr; + RwInt32 numBytesToWrite = size * count; + + assert(addr); + assert(fptr); + + bytesWritten = sceWrite(fp->gdfs, (void *)addr, numBytesToWrite); + + if (-1 != bytesWritten) + { + fp->POS += bytesWritten; + if (fp->POS > fp->SOF) + fp->SOF = fp->POS; + return (size > 0 ? bytesWritten / size : 0); + } + return (0); +} + +/**************************************************************************** + skyFseek + + On entry : file to seek in, offset, how to seek + On exit : 0 on success + */ + +static int +skyFseek(void *fptr, long offset, int origin) +{ + skyFile *fp = (skyFile *) fptr; + RwInt32 oldFPos, bufStart; + RwBool noBuffer = FALSE; + + assert(fptr); + + oldFPos = fp->POS; + bufStart = oldFPos - fp->bufferPos; + if (fp->bufferPos == READBUFFERSIZE) + noBuffer = TRUE; + fp->bufferPos = READBUFFERSIZE; + + switch (origin) + { + case SEEK_CUR: + { + /* Does the seek stay in the buffer */ + if (((oldFPos + offset >= bufStart) && + (oldFPos + offset < bufStart + READBUFFERSIZE)) && + (!noBuffer)) + { + fp->bufferPos = (oldFPos + offset) - bufStart; + fp->POS += offset; + } + else + { + fp->POS = + sceLseek(fp->gdfs, oldFPos + offset, + SCE_SEEK_SET); + } + break; + } + case SEEK_END: + { + fp->POS = sceLseek(fp->gdfs, offset, SCE_SEEK_END); + break; + } + case SEEK_SET: + { + fp->POS = sceLseek(fp->gdfs, offset, SCE_SEEK_SET); + break; + } + default: + { + return (-1); + } + } + + if (noBuffer) + fp->bufferPos = READBUFFERSIZE; + + if (fp->POS == -1) + { + /* This may not be valid */ + fp->POS = oldFPos; + fp->bufferPos = READBUFFERSIZE; + return (-1); + } + + return (0); +} + +/**************************************************************************** + skyFtell + + On entry : file to tell offset in + On exit : current offset in file + */ + +static int +skyFtell(void *fptr) +{ + skyFile *fp = (skyFile *) fptr; + + assert(fptr); + + return sceLseek(fp->gdfs, 0, SCE_SEEK_CUR); +} + +/**************************************************************************** + skyFgets + + On entry : Buffer to read into, max chars to read, file to read from + On exit : Returns pointer to string on success + */ + +static RwChar * +skyFgets(RwChar * buffer, int maxLen, void *fptr) +{ + skyFile *fp = (skyFile *) fptr; + RwInt32 i; + RwInt32 numBytesRead; + + assert(buffer); + assert(fptr); + + i = 0; + + numBytesRead = skyFread(buffer, 1, maxLen - 1, fp); + + if (numBytesRead == 0) + { + return (0); + } + + while (i < numBytesRead) + { + if (buffer[i] == '\n') + { + i++; + + buffer[i] = '\0'; + + /* the file pointer needs */ + /* to be reset as skyFread */ + /* will have overshot the */ + /* first new line */ + + i -= numBytesRead; + skyFseek(fp, i, SEEK_CUR); + + return (buffer); + } + else if (buffer[i] == 0x0D) + { + if ((i < (numBytesRead - 1)) && (buffer[i + 1] == '\n')) + { + memcpy(&buffer[i], &buffer[i + 1], + (numBytesRead - i - 1)); + numBytesRead--; + } + else + i++; + } + else + i++; + } + + /* + * Don't return NULL because we could have read maxLen bytes + * without finding a \n + */ + return (buffer); +} + +/**************************************************************************** + skyFputs + + On entry : Buffer to write from, file to write to + On exit : Non negative value on success + */ + +static int +skyFputs(const RwChar * buffer, void *fptr) +{ + skyFile *fp = (skyFile *) fptr; + int i, j; + + assert(buffer); + assert(fptr); + + i = strlen(buffer); + j = sceWrite(fp->gdfs, (void *) buffer, i); + + if (j != -1) + { + fp->POS += j; + if (fp->POS > fp->SOF) + fp->SOF = fp->POS; + } + if ((j == -1) || (i != j)) + { + return (EOF); + } + return (j); +} + +/**************************************************************************** + skyFeof + + On entry : File to test for end of + On exit : Non zero if end of file reached + */ + +static int +skyFeof(void *fptr) +{ + skyFile *fp = (skyFile *) fptr; + + assert(fptr); + + return (fp->POS >= fp->SOF); +} + +/**************************************************************************** + skyFflush + + On entry : + On exit : + */ + +static int +skyFflush(void *fptr __RWUNUSED__) +{ + return (0); +} + +/**************************************************************************** + _rwSkyFSOpen + + On entry : Instance, offset, size + On exit : instance pointer on success + */ + +static void * +_rwSkyFSOpen(void *instance, RwInt32 offset, RwInt32 size __RWUNUSED__) +{ + RwFileFunctions *FS; + + /* Cache the globals offset */ + gdfsModuleInfo.globalsOffset = offset; + + /* Create a free list for file handle structures */ + RWGDFSGLOBAL(fpFreeList) = RwFreeListCreate(sizeof(skyFile), 5, 0); + if (!RWGDFSGLOBAL(fpFreeList)) + { + return (NULL); + } + + /* This is per instance of RenderWare */ + FS = RwOsGetFileInterface(); + + /* save away the old filing system */ + RWGDFSGLOBAL(oldFS) = *FS; + + /* attach the new filing system */ + FS->rwfexist = skyFexist; /* FS->rwfexist; */ + FS->rwfopen = skyFopen; + FS->rwfclose = skyFclose; + FS->rwfread = skyFread; + FS->rwfwrite = skyFwrite; + FS->rwfgets = skyFgets; + FS->rwfputs = skyFputs; + FS->rwfeof = skyFeof; + FS->rwfseek = skyFseek; + FS->rwfflush = skyFflush; + FS->rwftell = skyFtell; + + gdfsModuleInfo.numInstances++; + + return (instance); +} + +/**************************************************************************** + _rwSkyFSClose + + On entry : instance, offset, size + On exit : instance pointer on success + */ + +static void * +_rwSkyFSClose(void *instance, RwInt32 offset __RWUNUSED__, + RwInt32 size __RWUNUSED__) +{ + RwFileFunctions *FS; + + FS = RwOsGetFileInterface(); + + /* re-attach the old filing system - not strictly necessary, + * but we are feeling kind today! */ + *FS = RWGDFSGLOBAL(oldFS); + + /* Blow away our free list */ + RwFreeListDestroy(RWGDFSGLOBAL(fpFreeList)); + + gdfsModuleInfo.numInstances--; + + return (instance); +} + +/**************************************************************************** + RwSkyInstallFileSystem + + On entry : + On exit : TRUE on success + */ + +RwBool +SkyInstallFileSystem(void) +{ + +// gdfsOpenFiles = 0; + + if (RwEngineRegisterPlugin + (sizeof(gdfsGlobals), rwID_SKYDEVICEMODULE, _rwSkyFSOpen, + _rwSkyFSClose) < 0) + { + /* If it is negative, we've failed */ + return (FALSE); + } + + /* Hurrah */ + return (TRUE); +} diff --git a/src/skyfs.h b/src/skyfs.h new file mode 100644 index 0000000..f5a20ab --- /dev/null +++ b/src/skyfs.h @@ -0,0 +1,38 @@ + +/**************************************************************************** + * + * skyfs.h + * + * This file is a product of Criterion Software Ltd. + * + * This file is provided as is with no warranties of any kind and is + * provided without any obligation on Criterion Software Ltd. + * or Canon Inc. to assist in its use or modification. + * + * Criterion Software Ltd. and Canon Inc. will not, under any + * circumstances, be liable for any lost revenue or other damages + * arising from the use of this file. + * + * Copyright (c) 1999, 2000 Criterion Software Ltd. + * All Rights Reserved. + * + */ + +#if (!defined(SKYFS_H)) +#define SKYFS_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +RwBool SkyInstallFileSystem(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* (!defined(SKYFS_H)) */