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

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

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
*.c linguist-language=C
*.h linguist-language=C

235
.gitignore vendored Normal file
View File

@@ -0,0 +1,235 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# Visual studio User-specific files
*.suo
*.user
*.sln.docstates
# Visual studio files
*.VC.db
*.VC.VC.opendb
# Android build results
android/.cxx/
android/.idea/
android/.gradle/
android/build/
android/app/build/
android/app/.externalNativeBuild/
android/local.properties
*.iml
#XCode stuff
project.xcworkspace/
xcuserdata/
# Nintendo Console build results
build-3ds/
build-nds/
build-dsi/
build-n64/
build-gc/
build-wii/
build-wiiu/
build-switch/
classicube.nds
# SEGA console build results
build-32x/
build-saturn/
build-dc/
IP.BIN
ISO_FILES/
third_party/gldc/libGLdc.a
cd/
# Microsoft console build results
build-360/
main.exe
main.lib
misc/xbox/ps_coloured.inl
misc/xbox/ps_textured.inl
misc/xbox/vs_coloured.inl
misc/xbox/vs_textured.inl
# Sony console build results
build-ps2/
build-ps3/
build-ps4/
build-psp/
build-vita/
EBOOT.PBP
PARAM.SFO
param.sfo
eboot.bin
pkg.gp4
# Desktop build results
build-amiga-68k/
# Build results
[Dd]ebug/
[Rr]elease/
x64/
x86/
build/
[Bb]in/
[Oo]bj/
[Oo]utput/
[Pp]rofilingSessions/
src/.vs/
# ClassiCube game files
src/audio
src/texpacks
src/maps
src/texturecache
src/logs
src/options.txt
src/ClassiCube*
src/screenshots
src/fontscache.txt
# ClassiCube game files
audio
texpacks
maps
texturecache
logs
options.txt
ClassiCube*
screenshots
fontscache.txt
# DOS files
CWSDPMI.EXE
CWSDPMI.SWP
OPTIONS.TXT
# Android source files need to be included
!android/app/src/main/java/com/classicube
# Flatpak wrapper which needs to be included
!misc/flatpak/ClassiCubeLauncher
# CMake files
CMakeFiles/
CMakeCache.txt
#GCC object files
*.o
# Build dependency files
*.d
# Roslyn cache directories
*.ide/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
#NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Mac classic
retro68scripts/
# PS2
openvcl/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
*.map
# Binary files
*.bin
*.elf
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# Installshield output folder
[Ee]xpress/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# If using the old MSBuild-Integrated Package Restore, uncomment this:
#!**/packages/repositories.config
# Windows Azure Build Output
csx/
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# Eclipse
.cproject
.project

350
Makefile Normal file
View File

@@ -0,0 +1,350 @@
SOURCE_DIR = src
BUILD_DIR = build
C_SOURCES = $(wildcard $(SOURCE_DIR)/*.c)
OBJECTS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(C_SOURCES))
BUILD_DIRS = $(BUILD_DIR) $(BUILD_DIR)/src
##############################
# Configurable flags and names
##############################
# Flags passed to the C compiler
CFLAGS = -pipe -fno-math-errno -Werror -Wno-error=missing-braces -Wno-error=strict-aliasing
# Flags passed to the linker
LDFLAGS = -g -rdynamic
# Name of the main executable
ENAME = ClassiCube
# Name of the final target file
# (usually this is the executable, but e.g. is the app bundle on macOS)
TARGET := $(ENAME)
# Enables dependency tracking (https://make.mad-scientist.net/papers/advanced-auto-dependency-generation/)
# This ensures that changing a .h file automatically results in the .c files using it being auto recompiled when next running make
# On older systems the required GCC options may not be supported - in which case just change TRACK_DEPENDENCIES to 0
TRACK_DEPENDENCIES=1
# link using C Compiler by default
LINK = $(CC)
#################################################################
# Determine shell command used to remove files (for "make clean")
#################################################################
ifndef RM
# No prefined RM variable, try to guess OS default
ifeq ($(OS),Windows_NT)
RM = del
else
RM = rm -f
endif
endif
###########################################################
# If target platform isn't specified, default to current OS
###########################################################
ifndef $(PLAT)
ifeq ($(OS),Windows_NT)
PLAT = mingw
else
PLAT = $(shell uname -s | tr '[:upper:]' '[:lower:]')
endif
endif
#########################################################
# Setup environment appropriate for the specific platform
#########################################################
ifeq ($(PLAT),web)
CC = emcc
OEXT = .html
CFLAGS = -g
LDFLAGS = -g -s WASM=1 -s NO_EXIT_RUNTIME=1 -s ABORTING_MALLOC=0 -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_STACK=256Kb --js-library $(SOURCE_DIR)/interop_web.js
BUILD_DIR = build/web
endif
ifeq ($(PLAT),mingw)
CC = gcc
OEXT = .exe
CFLAGS += -DUNICODE
LDFLAGS = -g
LIBS = -mwindows -lwinmm
BUILD_DIR = build/win
endif
ifeq ($(PLAT),linux)
LIBS = -lX11 -lXi -lpthread -lGL -ldl
BUILD_DIR = build/linux
BEARSSL = 1
endif
ifeq ($(PLAT),sunos)
LIBS = -lsocket -lX11 -lXi -lGL
BUILD_DIR = build/solaris
BEARSSL = 1
endif
ifeq ($(PLAT),hp-ux)
CC = gcc
LDFLAGS =
LIBS = -lm -lX11 -lXi -lXext -L/opt/graphics/OpenGL/lib -lGL -lpthread
BUILD_DIR = build/hpux
BEARSSL = 1
endif
ifeq ($(PLAT),darwin)
OBJECTS += $(BUILD_DIR)/src/Window_cocoa.o
LIBS =
LDFLAGS = -rdynamic -framework Cocoa -framework OpenGL -framework IOKit -lobjc
BUILD_DIR = build/macos
TARGET = $(ENAME).app
endif
ifeq ($(PLAT),freebsd)
CFLAGS += -I /usr/local/include
LDFLAGS = -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/freebsd
BEARSSL = 1
endif
ifeq ($(PLAT),openbsd)
CFLAGS += -I /usr/X11R6/include -I /usr/local/include
LDFLAGS = -L /usr/X11R6/lib -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/openbsd
BEARSSL = 1
endif
ifeq ($(PLAT),netbsd)
CFLAGS += -I /usr/X11R7/include -I /usr/pkg/include
LDFLAGS = -L /usr/X11R7/lib -L /usr/pkg/lib -rdynamic -Wl,-R/usr/X11R7/lib
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/netbsd
BEARSSL = 1
endif
ifeq ($(PLAT),dragonfly)
CFLAGS += -I /usr/local/include
LDFLAGS = -L /usr/local/lib -rdynamic
LIBS = -lexecinfo -lGL -lX11 -lXi -lpthread
BUILD_DIR = build/flybsd
BEARSSL = 1
endif
ifeq ($(PLAT),haiku)
OBJECTS += $(BUILD_DIR)/src/Platform_BeOS.o $(BUILD_DIR)/src/Window_BeOS.o
CFLAGS = -pipe -fno-math-errno
LDFLAGS = -g
LINK = $(CXX)
LIBS = -lGL -lnetwork -lbe -lgame -ltracker
BUILD_DIR = build/haiku
BEARSSL = 1
endif
ifeq ($(PLAT),beos)
OBJECTS += $(BUILD_DIR)/src/Platform_BeOS.o $(BUILD_DIR)/src/Window_BeOS.o
CFLAGS = -pipe
LDFLAGS = -g
LINK = $(CXX)
LIBS = -lGL -lnetwork -lbe -lgame -ltracker
BUILD_DIR = build/beos
TRACK_DEPENDENCIES=0
endif
ifeq ($(PLAT),serenityos)
LIBS = -lgl -lSDL2
BUILD_DIR = build/serenity
BEARSSL = 1
endif
ifeq ($(PLAT),irix)
CC = gcc
LIBS = -lGL -lX11 -lXi -lpthread -ldl
BUILD_DIR = build/irix
BEARSSL = 1
endif
ifeq ($(PLAT),dos)
CC = i586-pc-msdosdjgpp-gcc
LIBS =
LDFLAGS = -g
OEXT = .exe
BUILD_DIR = build/dos
endif
ifdef SDL2
CFLAGS += -DCC_WIN_BACKEND=CC_WIN_BACKEND_SDL2
LIBS += -lSDL2
endif
ifdef SDL3
CFLAGS += -DCC_WIN_BACKEND=CC_WIN_BACKEND_SDL3
LIBS += -lSDL3
endif
ifdef TERMINAL
CFLAGS += -DCC_WIN_BACKEND=CC_WIN_BACKEND_TERMINAL -DCC_GFX_BACKEND=CC_GFX_BACKEND_SOFTGPU
LIBS := $(subst mwindows,mconsole,$(LIBS))
endif
ifdef BEARSSL
BUILD_DIRS += $(BUILD_DIR)/third_party/bearssl/src
BEARSSL_SOURCES = $(wildcard third_party/bearssl/src/*.c)
BEARSSL_OBJECTS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(BEARSSL_SOURCES))
OBJECTS += $(BEARSSL_OBJECTS)
CFLAGS += -Ithird_party/bearssl/inc -DCC_SSL_BACKEND=CC_SSL_BACKEND_BEARSSL -DCC_NET_BACKEND=CC_NET_BACKEND_BUILTIN
endif
ifdef RELEASE
CFLAGS += -O1
else
CFLAGS += -g
endif
default: $(PLAT)
# Build for the specified platform
web:
$(MAKE) $(TARGET) PLAT=web
linux:
$(MAKE) $(TARGET) PLAT=linux
mingw:
$(MAKE) $(TARGET) PLAT=mingw
sunos:
$(MAKE) $(TARGET) PLAT=sunos
hp-ux:
$(MAKE) $(TARGET) PLAT=hp-ux
darwin:
$(MAKE) $(TARGET) PLAT=darwin
freebsd:
$(MAKE) $(TARGET) PLAT=freebsd
openbsd:
$(MAKE) $(TARGET) PLAT=openbsd
netbsd:
$(MAKE) $(TARGET) PLAT=netbsd
dragonfly:
$(MAKE) $(TARGET) PLAT=dragonfly
haiku:
$(MAKE) $(TARGET) PLAT=haiku
beos:
$(MAKE) $(TARGET) PLAT=beos
serenityos:
$(MAKE) $(TARGET) PLAT=serenityos
irix:
$(MAKE) $(TARGET) PLAT=irix
dos:
$(MAKE) $(TARGET) PLAT=dos
# Default overrides
sdl2:
$(MAKE) $(TARGET) SDL2=1
sdl3:
$(MAKE) $(TARGET) SDL3=1
terminal:
$(MAKE) $(TARGET) TERMINAL=1
release:
$(MAKE) $(TARGET) RELEASE=1
# Some builds require more complex handling, so are moved to
# separate makefiles to avoid having one giant messy makefile
32x:
$(MAKE) -f misc/32x/Makefile
saturn:
$(MAKE) -f misc/saturn/Makefile
dreamcast:
$(MAKE) -f misc/dreamcast/Makefile
psp:
$(MAKE) -f misc/psp/Makefile
vita:
$(MAKE) -f misc/vita/Makefile
ps1:
$(MAKE) -f misc/ps1/Makefile
ps2:
$(MAKE) -f misc/ps2/Makefile
ps3:
$(MAKE) -f misc/ps3/Makefile
ps4:
$(MAKE) -f misc/ps4/Makefile
xbox:
$(MAKE) -f misc/xbox/Makefile
xbox360:
$(MAKE) -f misc/xbox360/Makefile
n64:
$(MAKE) -f misc/n64/Makefile
gba:
$(MAKE) -f misc/gba/Makefile
ds:
$(MAKE) -f misc/ds/Makefile
3ds:
$(MAKE) -f misc/3ds/Makefile
gamecube:
$(MAKE) -f misc/gc/Makefile
wii:
$(MAKE) -f misc/wii/Makefile
wiiu:
$(MAKE) -f misc/wiiu/Makefile
switch:
$(MAKE) -f misc/switch/Makefile
os/2:
$(MAKE) -f misc/os2/Makefile
macclassic_68k:
$(MAKE) -f misc/macclassic/Makefile_68k
macclassic_ppc:
$(MAKE) -f misc/macclassic/Makefile_ppc
amiga_68k:
$(MAKE) -f misc/amiga/Makefile_68k
amiga_ppc:
$(MAKE) -f misc/amiga/Makefile_ppc
# Cleans up all build .o files
clean:
$(RM) $(OBJECTS)
#################################################
# Source files and executable compilation section
#################################################
# Auto creates directories for build files (.o and .d files)
$(BUILD_DIRS):
mkdir -p $@
# Main executable (typically just 'ClassiCube' or 'ClassiCube.exe')
$(ENAME): $(BUILD_DIRS) $(OBJECTS)
$(LINK) $(LDFLAGS) -o $@$(OEXT) $(OBJECTS) $(EXTRA_LIBS) $(LIBS)
@echo "----------------------------------------------------"
@echo "Successfully compiled executable file: $(ENAME)"
@echo "----------------------------------------------------"
# macOS app bundle
$(ENAME).app : $(ENAME)
mkdir -p $(TARGET)/Contents/MacOS
mkdir -p $(TARGET)/Contents/Resources
cp $(ENAME) $(TARGET)/Contents/MacOS/$(ENAME)
cp misc/macOS/Info.plist $(TARGET)/Contents/Info.plist
cp misc/macOS/appicon.icns $(TARGET)/Contents/Resources/appicon.icns
# === Compiling with dependency tracking ===
# NOTE: Tracking dependencies might not work on older systems - disable this if so
ifeq ($(TRACK_DEPENDENCIES), 1)
DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.d
DEPFILES := $(patsubst %.o, %.d, $(OBJECTS))
$(DEPFILES):
$(BUILD_DIR)/%.o : %.c $(BUILD_DIR)/%.d
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o : %.cpp $(BUILD_DIR)/%.d
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o : %.m $(BUILD_DIR)/%.d
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS) -c $< -o $@
include $(wildcard $(DEPFILES))
# === Compiling WITHOUT dependency tracking ===
else
$(BUILD_DIR)/%.o : %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o : %.cpp
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c $< -o $@
endif
# EXTRA_CFLAGS and EXTRA_LIBS are not defined in the makefile intentionally -
# define them on the command line as a simple way of adding CFLAGS/LIBS

119
android/app/CMakeLists.txt Normal file
View File

@@ -0,0 +1,119 @@
#
# Copyright (C) The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
cmake_minimum_required(VERSION 3.4.1)
# build native_app_glue as a static lib
set(${CMAKE_C_FLAGS}, "${CMAKE_C_FLAGS}")
# now build app's shared lib
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -Wall -Werror")
add_library(classicube SHARED
../../src/main.c
../../src/IsometricDrawer.c
../../src/Builder.c
../../src/ExtMath.c
../../src/_ftbitmap.c
../../src/Utils.c
../../src/Camera.c
../../src/Game.c
../../src/GameVersion.c
../../src/Window_Android.c
../../src/_ftbase.c
../../src/Graphics_GL2.c
../../src/Deflate.c
../../src/_cff.c
../../src/_ftsynth.c
../../src/String.c
../../src/LWidgets.c
../../src/Options.c
../../src/Drawer2D.c
../../src/Server.c
../../src/Entity.c
../../src/Drawer.c
../../src/Vorbis.c
../../src/Protocol.c
../../src/World.c
../../src/SelOutlineRenderer.c
../../src/Platform_Posix.c
../../src/Platform_Android.c
../../src/LScreens.c
../../src/_truetype.c
../../src/_ftglyph.c
../../src/Model.c
../../src/_autofit.c
../../src/Vectors.c
../../src/HeldBlockRenderer.c
../../src/Inventory.c
../../src/Launcher.c
../../src/Block.c
../../src/LWeb.c
../../src/Stream.c
../../src/Lighting.c
../../src/Resources.c
../../src/PackedCol.c
../../src/Screens.c
../../src/Formats.c
../../src/_sfnt.c
../../src/Bitmap.c
../../src/EntityComponents.c
../../src/_pshinter.c
../../src/Http_Worker.c
../../src/MapRenderer.c
../../src/Audio.c
../../src/_ftinit.c
../../src/Event.c
../../src/Logger.c
../../src/Widgets.c
../../src/TexturePack.c
../../src/Menus.c
../../src/BlockPhysics.c
../../src/_psmodule.c
../../src/Chat.c
../../src/Gui.c
../../src/AxisLinesRenderer.c
../../src/Picking.c
../../src/_type1.c
../../src/_smooth.c
../../src/_psaux.c
../../src/Generator.c
../../src/Input.c
../../src/Particle.c
../../src/Physics.c
../../src/SelectionBox.c
../../src/EnvRenderer.c
../../src/Animations.c
../../src/LBackend.c
../../src/SystemFonts.c
../../src/Commands.c
../../src/EntityRenderers.c
../../src/Audio_SLES.c
../../src/TouchUI.c
../../src/LBackend_Android.c
../../src/InputHandler.c
../../src/MenuOptions.c
../../src/FancyLighting.c
../../src/Queue.c
)
# add lib dependencies
target_link_libraries(classicube
android
EGL
GLESv2
log
OpenSLES
jnigraphics)

29
android/app/build.gradle Normal file
View File

@@ -0,0 +1,29 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId = 'com.classicube.android.client'
minSdkVersion 13
targetSdkVersion 26
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=c++_static'
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'),
'proguard-rules.pro'
}
}
externalNativeBuild {
cmake {
version '3.10.2'
path 'CMakeLists.txt'
}
}
}

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.classicube.android.client"
android:versionCode="1370"
android:versionName="1.3.7">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18" />
<uses-sdk android:minSdkVersion="8" android:targetSdkVersion="26"/>
<application android:icon="@mipmap/ccicon" android:label="ClassiCube">
<provider
android:name="com.classicube.CCFileProvider"
android:authorities="com.classicube.android.client.provider"
android:exported="false"
android:grantUriPermissions="true" >
</provider>
<activity android:name="com.classicube.MainActivity" android:label="ClassiCube"
android:configChanges="orientation|screenSize|keyboard|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->

View File

@@ -0,0 +1,115 @@
package com.classicube;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
public class CCFileProvider extends ContentProvider
{
final static String[] DEFAULT_COLUMNS = { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE, MediaStore.MediaColumns.DATA };
File root;
@Override
public boolean onCreate() {
return true;
}
@Override
public void attachInfo(Context context, ProviderInfo info) {
super.attachInfo(context, info);
root = context.getExternalFilesDir(null); // getGameDataDirectory
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
File file = getFileForUri(uri);
// can be null when caller is requesting all columns
if (projection == null) projection = DEFAULT_COLUMNS;
ArrayList<String> cols = new ArrayList<String>(3);
ArrayList<Object> vals = new ArrayList<Object>(3);
for (String column : projection) {
if (column.equals(OpenableColumns.DISPLAY_NAME)) {
cols.add(OpenableColumns.DISPLAY_NAME);
vals.add(file.getName());
} else if (column.equals(OpenableColumns.SIZE)) {
cols.add(OpenableColumns.SIZE);
vals.add(file.length());
} else if (column.equals(MediaStore.MediaColumns.DATA)) {
cols.add(MediaStore.MediaColumns.DATA);
vals.add(file.getAbsolutePath());
}
}
// https://stackoverflow.com/questions/4042434/converting-arrayliststring-to-string-in-java
MatrixCursor cursor = new MatrixCursor(cols.toArray(new String[0]), 1);
cursor.addRow(vals.toArray());
return cursor;
}
@Override
public String getType(Uri uri) {
String path = uri.getEncodedPath();
int sepExt = path.lastIndexOf('.');
if (sepExt >= 0) {
String fileExt = path.substring(sepExt);
if (fileExt.equals(".png")) return "image/png";
}
return "application/octet-stream";
}
@Override
public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException("Readonly access");
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Readonly access");
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Readonly access");
}
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File file = getFileForUri(uri);
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
public static Uri getUriForFile(String path) {
// See AndroidManifest.xml for authority
return new Uri.Builder()
.scheme("content")
.authority("com.classicube.android.client.provider")
.encodedPath(Uri.encode(path, "/"))
.build();
}
File getFileForUri(Uri uri) {
String path = uri.getPath();
File file = new File(root, path);
file = file.getAbsoluteFile();
// security validation check
if (!file.getPath().startsWith(root.getPath())) {
throw new SecurityException("Resolved path lies outside app directory:" + path);
}
return file;
}
}

View File

@@ -0,0 +1,57 @@
package com.classicube;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
public class CCMotionListener implements View.OnGenericMotionListener {
MainActivity activity;
public CCMotionListener(MainActivity activity) {
this.activity = activity;
}
// https://developer.android.com/develop/ui/views/touch-and-input/game-controllers/controller-input#java
@Override
public boolean onGenericMotion(View view, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_MOVE) return false;
boolean source_joystick = (event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK;
boolean source_gamepad = (event.getSource() & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD;
if (source_joystick || source_gamepad) {
int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++) {
processJoystickInput(event, i);
}
processJoystickInput(event, -1);
return true;
}
return false;
}
void processJoystickInput(MotionEvent event, int historyPos) {
float x1 = getAxisValue(event, MotionEvent.AXIS_X, historyPos);
float y1 = getAxisValue(event, MotionEvent.AXIS_Y, historyPos);
float x2 = getAxisValue(event, MotionEvent.AXIS_Z, historyPos);
float y2 = getAxisValue(event, MotionEvent.AXIS_RZ, historyPos);
if (x1 != 0 || y1 != 0)
pushAxisMovement(MainActivity.CMD_GPAD_AXISL, x1, y1);
if (x2 != 0 || y2 != 0)
pushAxisMovement(MainActivity.CMD_GPAD_AXISR, x2, y2);
}
float getAxisValue(MotionEvent event, int axis, int historyPos) {
float value = historyPos < 0 ? event.getAxisValue(axis) :
event.getHistoricalAxisValue(axis, historyPos);
// Deadzone detection
if (value >= -0.25f && value <= 0.25f) value = 0;
return value;
}
void pushAxisMovement(int axis, float x, float y) {
activity.pushCmd(axis, (int)(x * 4096), (int)(y * 4096));
}
}

View File

@@ -0,0 +1,108 @@
package com.classicube;
import android.text.Editable;
import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
public class CCView extends SurfaceView {
SpannableStringBuilder kbText;
MainActivity activity;
public CCView(MainActivity activity) {
// setFocusable, setFocusableInTouchMode - API level 1
super(activity);
this.activity = activity;
setFocusable(true);
setFocusableInTouchMode(true);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return activity.handleTouchEvent(ev) || super.dispatchTouchEvent(ev);
}
@Override
public InputConnection onCreateInputConnection(EditorInfo attrs) {
// BaseInputConnection, IME_ACTION_GO, IME_FLAG_NO_EXTRACT_UI - API level 3
attrs.actionLabel = null;
attrs.inputType = MainActivity.calcKeyboardType(activity.keyboardType);
attrs.imeOptions = MainActivity.calcKeyboardOptions(activity.keyboardType);
kbText = new SpannableStringBuilder(activity.keyboardText);
InputConnection ic = new BaseInputConnection(this, true) {
boolean inited;
void updateText() {
activity.pushCmd(MainActivity.CMD_KEY_TEXT, kbText.toString());
}
@Override
public Editable getEditable() {
if (!inited) {
// needed to set selection, otherwise random crashes later with backspacing
// set selection to end, so backspacing after opening keyboard with text still works
Selection.setSelection(kbText, kbText.toString().length());
inited = true;
}
return kbText;
}
@Override
public boolean setComposingText(CharSequence text, int newCursorPosition) {
boolean success = super.setComposingText(text, newCursorPosition);
updateText();
return success;
}
@Override
public boolean deleteSurroundingText(int beforeLength, int afterLength) {
boolean success = super.deleteSurroundingText(beforeLength, afterLength);
updateText();
return success;
}
@Override
public boolean commitText(CharSequence text, int newCursorPosition) {
boolean success = super.commitText(text, newCursorPosition);
updateText();
return success;
}
@Override
public boolean sendKeyEvent(KeyEvent ev) {
// getSelectionStart - API level 1
if (ev.getAction() != KeyEvent.ACTION_DOWN) return super.sendKeyEvent(ev);
int code = ev.getKeyCode();
int uni = ev.getUnicodeChar();
// start is -1 sometimes, and trying to insert/delete there crashes
int start = Selection.getSelectionStart(kbText);
if (start == -1) start = kbText.toString().length();
if (code == KeyEvent.KEYCODE_ENTER) {
// enter maps to \n but that should not be intercepted
} else if (code == KeyEvent.KEYCODE_DEL) {
if (start <= 0) return false;
kbText.delete(start - 1, start);
updateText();
return false;
} else if (uni != 0) {
kbText.insert(start, String.valueOf((char) uni));
updateText();
return false;
}
return super.sendKeyEvent(ev);
}
};
//String text = MainActivity.this.keyboardText;
//if (text != null) ic.setComposingText(text, 0);
return ic;
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

21
android/build.gradle Normal file
View File

@@ -0,0 +1,21 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.4'
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

20
android/gradle.properties Normal file
View File

@@ -0,0 +1,20 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
android.enableJetifier=true
android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Fri May 06 22:33:57 AEST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

164
android/gradlew vendored Normal file
View File

@@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
android/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

2
android/settings.gradle Normal file
View File

@@ -0,0 +1,2 @@
include ':app'

22
credits.txt Normal file
View File

@@ -0,0 +1,22 @@
* Goodlyay - many suggestions, and being a great second pairs of eyes for issues and
improvements with character modelling, animating, and view bobbing. Also designed the icons.
Also designed all the textures in the web client. Big thanks!
* AndrewPH - Advice on how to improve ui of both client and launcher, multiple
suggestions, and hosting the automatic build bot for ClassiCube.
* 123DMWM - many suggestions, and assistance in identifying bugs and their causes.
* video_error - Allowing remote use of an macOS machine, pointing out many flaws in the plugin API.
The macOS port would not have been possible without you, thanks!
* Jerralish - reverse engineering and documenting the original classic map generation algorithm.
* Cybertoon - Adding water animation, better metal step/dig sounds, identifying multiple flaws
* Cheesse - multiple suggestions, testing ClassicalSharp on AMD graphics cards.
* Hemsindor - testing ClassicalSharp on macOS.
* headshotnoby - developing the Switch port.
* Beyond_5D - identifying many differences from original Classic
And a big thanks to everyone else in the ClassiCube community (who I didn't mention here),
who in the past have provided many suggestions and assisted in identifying bugs.
* Portions of the FreeType project (https://www.freetype.org/) are used for text rendering
Some functionality has been removed compared to original FreeType source code.
Additionally, the base .c files have an #ifdef to disable compiling for emscripten
The source code of FreeType is otherwise unmodified.

37
doc/compile-fixes.md Normal file
View File

@@ -0,0 +1,37 @@
Visual studio unsupported platform toolset
---------------------
To fix the ```Error MSB8036 The Windows SDK version 5.1 was not found. Install the required version of Windows SDK or change the SDK version in the project property pages or by right-clicking the solution and selecting "Retarget solution"```
* Right click **ClassiCube** project (it's under the *Solution 'ClassiCube'* in the *Solution Explorer* pane)
* Click **Properties**
* Make sure you are in **General** tab under **Configuration Properties**
* You should see a dropdown named **Platform Toolset**. Click on it.
* Change it to one of the toolsets in the list that pops up.
* Click **OK**. You should be able to compile now
![image](https://user-images.githubusercontent.com/6509348/60266950-727e4780-992c-11e9-98fb-85eb34959e93.png)
Common compilation errors
---------------------
#### Undefined reference to 'clock_gettime'
Add ```-lrt``` when compiling. Occurs when using glibc versions before 2.17.
#### fatal error: execinfo.h: No such file or directory
Define `CC_BACKTRACE_BUILTIN` when compiling. Usually occurs when using musl.
#### Undefined reference to 'backtrace'
Define `CC_BACKTRACE_BUILTIN` when compiling. Usually occurs when using musl.
Webclient patches
---------------------
#### Mouse scrolling not properly prevented
With recent chrome/firefox versions, page is still scrolled and console is spammed with\
```"[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive."```
You need to to register events as a passive handler. Look for something like:
```
eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, eventHandler.useCapture);
```
and change to
```
eventHandler.target.addEventListener(eventHandler.eventTypeString, jsEventHandler, { useCapture: eventHandler.useCapture, passive: false });
```

186
doc/hosting-flask.md Normal file
View File

@@ -0,0 +1,186 @@
The page provides a complete example for how to integrate the webclient into a simple website
The example website will be structured like so:
```
websrv.py
templates/play.html
static/classisphere.js
static/default.zip
static/style.css
static/jquery.js
```
## Content
#### websrv.py
```Python
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route("/")
def index():
return '<html><h1>Welcome!</h1>Click <a href="/play">here</a> to play</h1></html>'
@app.route("/play")
@app.route("/play/")
def play():
user = request.args.get('user') or 'Singleplayer'
ver = request.args.get('mppass') or ''
addr = request.args.get('ip')
port = request.args.get('port') or '25565'
if addr:
args = "['%s', '%s', '%s', '%s']" % (user, ver, addr, port)
else:
args = "['%s']" % user
return render_template('play.html', game_args=args)
if __name__ == "__main__":
app.run()
```
#### templates/play.html
```HTML
{% set mobile_mode = request.user_agent.platform in ('android', 'iphone', 'ipad') %}
<html>
<head>
<meta name="viewport" content="width=device-width">
<link href="/static/style.css" rel="stylesheet">
<script src="/static/jquery.js"></script>
</head>
<body>
{% if mobile_mode %}
<style>
#body {min-height: 0px;}
.sec {padding: 0px;}
.row {padding: 0px;}
</style>
{% else %}
<div id="header">
<div class="row">
<a href="/"><h1 class="columns">Home</h1></a>
<a href="/play"><h1 class="columns">Play</h1></a>
</div>
</div>
{% endif %}
<div id="body">
<div class="sec">
<div class="row">
<canvas id="canvas" style="display:block; box-sizing:border-box; border-width:0px; padding:0; margin:0 auto; background-color: black; width:100%; height:auto;"
oncontextmenu="event.preventDefault()" tabindex=-1 width="1000" height="562"></canvas>
<span id="logmsg" style="font-size:18px;color:#F67;"></span>
</div>
</div>
<script type='text/javascript'>
function resizeGameCanvas() {
var cc_canv = $('canvas#canvas');
var dpi = window.devicePixelRatio;
var aspect_ratio = 16/9;
var viewport_w = cc_canv.parent().width();
var viewport_h = viewport_w / aspect_ratio;
var canv_w = Math.round(viewport_w);
var canv_h = Math.round(viewport_h);
if (canv_h % 2) { canv_h = canv_h - 1; }
if (canv_w % 2) { canv_w = canv_w - 1; }
{% if mobile_mode %}
var screen_h = Math.min(window.innerHeight, window.outerHeight || window.innerHeight);
canv_h = screen_h;
{% endif %}
cc_canv[0].width = canv_w * dpi;
cc_canv[0].height = canv_h * dpi;
}
var Module = {
preRun: [ resizeGameCanvas ],
postRun: [],
arguments: {{game_args|safe}},
print: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
},
printErr: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() { return document.getElementById('canvas'); })(),
setStatus: function(text) {
console.log(text);
document.getElementById('logmsg').innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
};
Module.setStatus('Downloading...');
window.onerror = function(msg) {
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
Module.setStatus('Exception thrown, see JavaScript console (' + msg + ')');
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
</script>
<script async type="text/javascript" src="/static/classisphere.js"></script>
</div>
</body>
</html>
```
#### static/classisphere.js
Download `cs.classicube.net/client/latest/ClassiCube.js` for this
#### static/default.zip
Download `classicube.net/static/default.zip` for this
#### static/style.css
```CSS
body { margin: 0; }
.row {
margin-left: auto;
margin-right: auto;
max-width: 62.5em;
}
a { text-decoration: none; }
.columns { display: inline-block; }
.sec {
background:#f1ecfa;
padding:10px 0 5px;
}
#header { background-color:#5870b0; }
#header h1 {
color:#fff;
margin:0px 10px 0px 10px;
width: 200px;
}
```
#### static/jquery.js
Download some version of jQuery for this. Version 2.1.1 is known to work.
## Notes
* If you don't want the game to resize to fit different resolutions, remove the `resizeGameCanvas` code.
* mobile_mode is used to deliver a minified page for mobile/tablet devices
## Results
After all this setup, you need to install the flask package for python.
Then in command prompt/terminal enter: `python websrv.py`
Then navigate to `http://127.0.0.1:5000/play` in your web browser. If all goes well you should see the web client start in singleplayer.
To start in multiplayer instead, navigate to `http://127.0.0.1:5000/play?user=test&ip=127.0.0.1&port=25565`

97
doc/hosting-webclient.md Normal file
View File

@@ -0,0 +1,97 @@
Hosting your own version of the ClassiCube webclient is relatively straightforward
Only the following 3 files are required:
1) A web page to initialise the game .js and display the game
2) The game .js file
3) The default texture pack
TODO: more advanced sample (authentication, custom game.js, skin server)
### Example setup
For example, let's assume your website is setup like this:
* `example.com/play.html`
* `example.com/static/classisphere.js`
* `example.com/static/default.zip`
For simplicitly,
1) Download `cs.classicube.net/client/latest/ClassiCube.js`, then upload it to `static/classisphere.js` on the webserver
2) Download `classicube.net/static/default.zip`, then upload it to `static/default.zip` on the webserver
The play.html page is the trickiest part, because how to implement this is website-specific. (depends on how the website is styled, what webserver is used, what programming language is used to generate the html, etc)
#### Changing where the game downloads the texture pack from
There should be this piece of code somewhere in the .JS file: `function _interop_AsyncDownloadTexturePack(rawPath) {`
A bit below that, there should be `var url = '/static/default.zip';` - change that to the desired URL.
#### Embedding the game in play.html
The following HTML code is required to be somewhere in the webpage:
```HTML
<!-- the canvas *must not* have any border or padding, or mouse coords will be wrong -->
<canvas id="canvas" style="display:block; border:0; padding:0; background-color: black;"
oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
<span id="logmsg"></span>
<script type='text/javascript'>
var Module = {
preRun: [],
postRun: [],
arguments: [ {username}, {mppass}, {server ip}, {server port} ],
print: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
},
printErr: function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
},
canvas: (function() { return document.getElementById('canvas'); })(),
setStatus: function(text) {
console.log(text);
document.getElementById('logmsg').innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
}
};
Module.setStatus('Downloading...');
window.onerror = function(msg) {
// TODO: do not warn on ok events like simulating an infinite loop or exitStatus
Module.setStatus('Exception thrown, see JavaScript console (' + msg + ')');
Module.setStatus = function(text) {
if (text) Module.printErr('[post-exception status] ' + text);
};
};
</script>
<script async type="text/javascript" src="/static/classisphere.js"></script>
```
**To start in singleplayer instead, just use `arguments: [ {username} ],` instead**
##### Variables
* {username} - the player's username
* {mppass} - if server verifies names, [mppass](https://wiki.vg/Classic_Protocol#User_Authentication). Otherwise leave as `''`.
* {server ip} - the IP address of the server to connect to
* {server port} - the port on the server to connect on (usually `'25565'`)
### Complete example
The links below show how to integrate the webclient into a simple website
* [Flask (python webserver)](hosting-flask.md)
### iOS / Android support
The webclient is compatible with Android / iOS devices and will show a touch based UI to these devices.
However, due to the limited screen size available on such devices, you should consider serving a webpage consisting of just the `<canvas>` to these devices - no header, footer or anything else.
Additionally, you will likely want to ensure zooming is disabled, viewport width is same as the device's width, and that 'add to device homescreen' is fully supported. You can accomplish that by adding these three HTML tags to the page:
```HTML
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
```

177
doc/menu-architecture.md Normal file
View File

@@ -0,0 +1,177 @@
## Introduction
The 2D GUI works by showing multiple 'screens' or 'layers' on top of each other. Each 'screen' usually contains one or more widgets. (e.g. a 'ButtonWidget' for a 'Close' button)
Here's an example of multiple screens:
![image](https://user-images.githubusercontent.com/6509348/103143562-a11cee80-476c-11eb-9e24-a854b069704f.png)
The example above consists of three screens:
1. `PauseScreen` - Top layer which consists of button widgets. Also draws a background to darken the screens/layers underneath it.
2. `ChatScreen` - Text widgets in the bottom left area (Only one is currently used though)
3. `HUDScreen` - Text in the top left and hotbar at the bottom
TODO: Explain event processing architecture
TODO: Explain pointer IDs. maybe a separate input-architecture.md file?
TODO: Explain dynamic vertex buffer
## Screen interface
#### `void Init(void* screen)`
Where you initialise state and objects that lasts for the entire duration the screen is open
E.g. Hooking into events
#### `void Free(void* screen)`
Where you undo the allocating/event hooking you did in `Init`.
#### `void ContextRecreated(void* screen)`
Where you allocate resources used for rendering, such as fonts, textures of widgets, and the screen's dynamic vertex buffer.
E.g. where you should call `ButtonWidget_SetConst`, `TextWidget_SetConst`, etc.
#### `void ContextLost(void* screen)`
Where you destroy/release all that resources that were allocated in `ContextRecreated`.
Note: You **MUST** destroy all the textures/vertex buffers that you allocated, as otherwise you will get an error later with 'recreating context failed' with the Direct3D9 backend when you next try to resize the window or go fullscreen. TODO: rewrite this note
#### `void Layout(void* screen)`
Where you reposition all the elements (i.e. widgets + anything else) of this screen.
Note: This is called when initially showing this screen, and whenever the window is resized
#### `int HandlesInputDown(void* screen, int button)`
Called whenever a input button (keyboard/mouse/gamepad) is pressed.
#### `void OnInputUp(void* screen, int button)`
Called whenever a input button (keyboard/mouse/gamepad) is released.
#### `int HandlesKeyPress(void* screen, char keyChar)`
Called when a key character is entered on the keyboard.
E.g. you'd get '$' here if user pressed 4 while holding shift)
#### `int HandlesTextChanged(void* screen, const cc_string* str)`
Called when the text changes in the on-screen keyboard. (i.e. KeyPress but for mobile text input)
#### `int HandlesMouseScroll(void* screen, float wheelDelta)`
Called when the wheel is scrolled on the mouse.
#### `int HandlesPointerDown(void* screen, int pointerID, int x, int y)`
Called whenever the left mouse or a touch finger is pressed.
#### `void OnPointerUp(void* screen, int pointerID, int x, int y)`
Called whenever the left mouse or a touch finger is released.
#### `int HandlesPointerMove(void* screen, int pointerID, int x, int y)`
Called whenever the left mouse or a touch finger is moved.
#### `void BuildMesh(void* screen)`
Where you fill out the screen's dynamic vertex buffer with the vertices of all the widgets.
Note: This gets called just before `Render()` whenever the `dirty` field is set to `true`.
Note: Pointer/Input events automatically set the `dirty` field to `true` for the next frame
#### `void Update(void* screen, double delta)`
Called just before `Render()` every frame and also provides the elapsed time since last render.
Typically you'd use this to update simple stuff that depends on accumulated time.
(E.g. whether the flashing caret should appear or not for input widgets)
#### `void Render(void* screen)`
Called every frame and is where you actually draw the widgets and other stuff on-screen.
## Screen members
#### `struct ScreenVTABLE* VTABLE`
Set to a `ScreenVTABLE` instance which implements all of the `Screen interface` functions
#### `cc_bool grabsInput`
Whether this screen grabs all input.
Note: If any screen grabs all input, then the mouse cursor becomes visible, W/A/S/D stops causing player movement, etc.
#### `cc_bool blocksWorld`
Whether this screen completely and opaquely covers the game world behind it.
E.g. loading screen and disconnect screen
#### `cc_bool closable`
Whether this screen is automatically closed when pressing Escape.
Note: Usually should be true for screens that are menus (e.g. pause screen)
#### `cc_bool dirty`
Whether this screen will have `BuildMesh()` called on the next frame
Note: This should be set to `true` whenever any event/actions that might alter the screen's appearance occurs TODO explain when automatically called?
#### `int maxVertices`
The maximum number of vertices that this screen's dynamic vertex buffer may use
#### `GfxResourceID vb`
This screen's dynamic vertex buffer
#### `struct Widget** widgets;`
Pointer to the array of pointers to widgets that are contained in this screen
#### `int numWidgets;`
The number of widgets that are contained in this screen
## Screen notes
* When the screen is shown via `Gui_Add`, the following functions are called
1) Init
2) ContextRecreated
3) Layout
4) HandlesPointerMove
* When the screen is removed via `Gui_Remove`, the following functions are called
1) ContextLost
2) Free
* When the screen is refreshed via `Gui_Refresh`, the following functions are called
1) ContextLost
2) ContextRecreated
3) Layout
Note: Whenever `default.png` (font texture) changes, `Gui_Refresh` is called for all screens. Therefore, fonts should usually be allocated/freed in `ContextRecreated/ContextLost` instead of `Init/Free` to ensure that the screen still looks correct after the texture pack changes.
TODO: Move this note earlier?
# Putting it altogether
TODO Add example of screen
Simple menu example that grabs all input
More complicated example too

124
doc/modules.md Normal file
View File

@@ -0,0 +1,124 @@
The overall source code is structured where each .c represents a particular module. These modules are:
TODO: explain multiple backends for some Modules
## 2D modules
|Module|Functionality|
|--------|-------|
|Bitmap|Represents a 2D array of pixels (and encoding/decoding to PNG)
|Drawer2D|Contains a variety of drawing operations on bitmaps (including text and fonts)
|PackedCol|32 bit RGBA color in a format suitable for using as color component of a vertex
|SystemFonts|Drawing, measuring, and retrieving the list of platform/system specific fonts
## Audio modules
|Module|Functionality|
|--------|-------|
|Audio|Playing music and dig/place/step sounds, and abstracts a PCM audio playing API
|Vorbis| Decodes [ogg vorbis](https://xiph.org/vorbis/) audio into PCM audio samples
## Entity modules
|Module|Functionality|
|--------|-------|
|Entity|Represents an in-game entity, and manages updating and rendering all entities
|EntityComponents|Various components that can be used by entities (e.g. tilt, animation, hacks state)
|Model|Contains the list of entity models, and provides relevant methods for entity models
|Particle|Represents particle effects, and manages rendering and spawning particles
## Game modules
|File|Functionality|
|--------|-------|
|Block|Stores properties and data for blocks (e.g. collide type, draw type, sound type)
|BlockPhysics|Implements simple block physics for singleplayer
|Camera|Represents a camera (can be first or third person)
|Chat|Manages sending, adding, logging and handling chat
|Game|Manages the overall game loop, state, and variables (e.g. renders a frame, runs scheduled tasks)
|Input|Manages keyboard, mouse, and touch state and events, and implements base handlers for them
|Inventory|Manages inventory hotbar, and ordering of blocks in the inventory menu
## Game gui modules
|File|Functionality|
|--------|-------|
|Gui|Describes and manages the 2D GUI elements on screen
|IsometricDrawer|Draws 2D isometric blocks for the hotbar and inventory UIs
|Menus|Contains all 2D non-menu screens (e.g. inventory, HUD, loading, chat)
|Screens|Contains all 2D menu screens (e.g. pause menu, keys list menu, font list menu)
|Widgets|Contains individual GUI widgets (e.g. button, label)
## Graphics modules
|Module|Functionality|
|--------|-------|
|Builder|Converts a 16x16x16 chunk into a mesh of vertices
|Drawer|Draws the vertices for a cuboid region
|Graphics|Abstracts a 3D graphics rendering API
## I/O modules
|Module|Functionality|
|--------|-------|
|Deflate|Decodes and encodes data compressed using DEFLATE (in addition to GZIP/ZLIB headers)
|Stream|Abstract reading and writing data to/from various sources in a streaming manner
## Launcher modules
|Module|Functionality|
|--------|-------|
|Launcher|Manages the overall launcher loop, state, and variables (e.g. resets pixels in areas, marks areas as needing to be redrawn)
|LBackend|Handles the rendering of widgets and forwarding input events to screens/menus
|LScreens|Contains all the menus in the launcher (e.g. servers list, updates menu, main menu)
|LWeb|Responsible for launcher related web requests (e.g. signing in, fetching servers list)
|LWidgets|Contains individual launcher GUI widgets (e.g. button, label, input textbox)
|Resources|Responsible for checking, downloading, and creating the default assets (e.g. default.zip, sounds)
## Map modules
|Module|Description|
|--------|-------|
|Formats|Imports/exports a world from/to several map file formats (e.g. .cw, .dat, .lvl)
|Generator|Generates a new world in either a flatgrass or Minecraft Classic style
|Lighting|Gets lighting colors at coordinates in the world
|World|Manages fixed size 3D array of blocks and associated environment metadata
## Math/Physics modules
|Module|Description|
|--------|-------|
|ExtMath|Math functions, math constants, and a Random Number Generator
|Physics|AABBs and geometry intersection
|Picking|Performs raytracing to e.g. determine the picked/selected block in the world
|Vectors|Contains vector,matrix,and frustum culling
## Network modules
|Module|Description|
|--------|-------|
|Http|Performs GET and POST requests in the background
|Protocol|Implements Minecraft Classic, CPE, and WoM environment protocols
|Server|Manages a connection to a singleplayer or multiplayer server
|SSL|Performs SSL/TLS encryption and decryption
## Platform modules
|Module|Description|
|--------|-------|
|Logger|Manages logging to client.log, and dumping state in both intentional and unhandled crashes
|Platform|Abstracts platform specific functionality. (e.g. opening a file, allocating memory, starting a thread)
|Program|Parses command line arguments, and then starts either the Game or Launcher
|Window|Abstracts creating and managing a window (e.g. setting titlebar text, entering fullscreen)
## Rendering modules
|Module|Description|
|--------|-------|
|AxisLinesRenderer|Renders 3 lines showing direction of each axis
|EnvRenderer|Renders environment of the world (clouds, sky, skybox, world sides/edges, etc)
|HeldBlockRenderer|Renders the block currently being held in bottom right corner
|MapRenderer|Renders the blocks of the world by diving it into chunks, and manages sorting/updating these chunks
|SelOutlineRenderer|Renders an outline around the block currently being looked at
|SelectionBox|Renders and stores selection boxes
## Texture pack modules
|Module|Functionality|
|--------|-------|
|Animations|Everything relating to texture animations (including default water/lava ones)
|TexturePack|Everything relating to texture packs (e.g. extracting .zip, terrain atlas, etc)
## Utility modules
|Module|Functionality|
|--------|-------|
|Event|Contains all events and provies helper methods for using events
|Options|Retrieves options from and sets options in options.txt
|String|Implements operations for a string with a buffer, length, and capacity
|Utils|Various general utility functions

171
doc/options.md Normal file
View File

@@ -0,0 +1,171 @@
Listed below are all of the options supported in options.txt
# Global options
### HTTP options
|Name|Default|Description|
|--|--|--|
`http-no-https`|`false`|Whether `https://` support is disabled<br>**Disabling means your account password is transmitted in plaintext**
`https-verify`|`false`|Whether to validate 'https://' certificates returned by webservers<br>**Disabling this is a bad idea, but is still less bad than `http-no-https`**
### Text drawing options
|Name|Default|Description|
|--|--|--|
`gui-arialchatfont`|`false`|Whether system fonts are used instead of default.png for drawing most text
`gui-blacktextshadows`|`false`|Whether text shadow color is pure black instead of faded
`gui-fontname`||Name of preferred system font to use for text rendering
### Window options
|Name|Default|Description|
|--|--|--|
`landscape-mode`|`false`|Whether to force landscape orientation<br>**Only supported on Android/iOS**
# Launcher options
### General options
|Name|Default|Description|
|--|--|--|
`autocloselauncher`|`false`|Whether to automatically close the launcher after the game is started
`launcher-cc-username`||Account username
`launcher-cc-password`||Encrypted account password
`nostalgia-classicbg`|false`|Whether to draw classic minecraft.net like background
### Web options
|Name|Default|Description|
|--|--|--|
`server-services`|`https://www.classicube.net/api`|URL for account services (login and server list)
`launcher-session`||Encrypted session cookie<br>Valid session cookies avoids MFA/2FA check
### Theme colors
|Name|Description|
|--|--|
`launcher-back-col`|Background/base color
`launcher-btn-border-col`|Color of border arround buttons
`launcher-btn-fore-active-col`|Color of button when mouse is hovered over
`launcher-btn-fore-inactive-col`|Normal color of buttons
`launcher-btn-highlight-inactive-col`|Color of line at top of buttons
### Direct connect
|Name|Description|
|--|--|
`launcher-dc-username`|Username to use when connecting
`launcher-dc-ip`|IP address or hostname to connect to
`launcher-dc-port`|Port to connect on
`launcher-dc-mppass`|Encrypted mppass to use when connecting
### Resume
|Name|Description|
|--|--|
`launcherserver`|Name of server to connect to<br>Hint for user, not actually used for connecting
`launcher-username`|Username to use when connecting
`launcher-ip`|IP address or hostname to connect to
`launcher-port`|Port to connect on
`launcher-mppass`|Encrypted mppass to use when connecting
# Game options
### Audio options
|Name|Default|Description|
|--|--|--|
`soundsvolume`|`0` for webclient<br>`100` elsewhere|Volume of game sounds (e.g. break/walk sounds)<br>Volume must be between 0 and 100
`musicvolume`|`0` for webclient<br>`100` elsewhere|Volume of game background music<br>Volume must be between 0 and 100
`music-mindelay`|`120` (2 minutes)|Minimum delay before next music track is played <br>Delay must be between 0 and 3600
`music-maxdelay`|`420` (7 minutes)|Maximum delay before next music track is played <br>Delay must be between 0 and 3600
### Block physics options
|Name|Default|Description|
|--|--|--|
`singleplayerphysics`|`true`|Whether block physics are enabled in singleplayer
### Chat options
|Name|Default|Description|
|--|--|--|
`chat-logging`|`false` for mobile/web<br>`true` elsewhere|Whether to log chat messages to disc
### HTTP options
|Name|Default|Description|
|--|--|--|
`http-skinserver`|`http://classicube.s3.amazonaws.com/skin`|URL where player skins are downloaded from
### Map rendering options
|Name|Default|Description|
|--|--|--|
`gfx-smoothlighting`|`false`|Whether smooth/advanced lighting is enabled
`gfx-maxchunkupdates`|`30`|Max number of chunks built in one frame<br>Must be between 4 and 1024
### Camera options
|Name|Default|Description|
|--|--|--|
`mousesensitivity`|`40` for Windows<br>`30` elsewhere|How sensitive camera rotation is to mouse movement<br>Sensitivity must be between 1 and 200
`hacks-fov`|`70`|Field of view<br>Must be between 1 and 179
`hacks-cameraclipping`|`true`|Whether third person camera is clipped to not go inside blocks
`invertmouse`|`true`|Whether vertical mouse movement direction is inverted
`camera-smooth`|`false`|Whether smooth camera mode is enabled
`cameramass`|`20`|How smooth the smooth camera is<br>Value must be between 1 and 100
### Game options
|Name|Default|Description|
|--|--|--|
./Game.c: Game_ClassicMode = Options_GetBool(OPT_CLASSIC_MODE, false);
./Game.c: Game_ClassicHacks = Options_GetBool(OPT_CLASSIC_HACKS, false);
./Game.c: Game_AllowCustomBlocks = Options_GetBool(OPT_CUSTOM_BLOCKS, true);
./Game.c: Game_UseCPE = Options_GetBool(OPT_CPE, true);
./Game.c: Game_SimpleArmsAnim = Options_GetBool(OPT_SIMPLE_ARMS_ANIM, false);
./Game.c: Game_ViewBobbing = Options_GetBool(OPT_VIEW_BOBBING, true);
./Game.c: Game_ViewDistance = Options_GetInt(OPT_VIEW_DISTANCE, 8, 4096, 512);
./Game.c: Game_BreakableLiquids = !Game_ClassicMode && Options_GetBool(OPT_MODIFIABLE_LIQUIDS, false);
./Game.c: Game_AllowServerTextures = Options_GetBool(OPT_SERVER_TEXTURES, true);
### Hacks options
|Name|Default|Description|
|--|--|--|
`hacks-hacksenabled`|`true`|Whether hacks are enabled at all<br>Has no effect in 'classic only' game mode
`hacks-speedmultiplier`|`10.0`|Speed multiplier/factor when speedhacks are active<br>Multiplier must be between 0.1 and 50.0
`hacks-pushbackplacing`|`false`|Whether to enable pushback placing mode
`hacks-noclipslide`|`false`|Whether to still slide for a bit after a movement button is released in noclip mode
`hacks-womstylehacks`|`false`|Whether to enable WoM client style hacks (e.g. ludicrous triple jump)
`hacks-fullblockstep`|`false`|Whether to automatically climb up 1.0 (default is only 0.5) tall blocks
`hacks-jumpvelocity`|`0.42`|Initial vertical velocity when you start a jump<br>Velocity must be between 0.0 and 52.0
`hacks-perm-msgs`|`true`|Whether to show a message in chat if you attempt to use a currently disabled hack
## General rendering options
|Name|Default|Description|
|--|--|--|
`gfx-mipmaps`|`false`|Whether to use mipmaps to reduce faraway texture noise
`fpslimit`|`LimitVSync`|Strategy used to limit FPS<br>Strategies: LimitVSync, Limit30FPS, Limit60FPS, Limit120FPS, Limit144FPS, LimitNone
`normal`|`normal`|Environmental effects render mode<br>Modes: normal, normalfast, legacy, legacyfast<br>- legacy improves appearance on some older GPUs<br>- fast disables clouds, fog and overhead sky
## Other rendering options
|Name|Default|Description|
|--|--|--|
`nostalgia-classicarm`|Classic mode|Whether to render your own arm in classic or modern minecraft style
`gui-blockinhand`|`true`|Whether to show block currently being held in bottom right corner
`namesmode`|`Hovered`|Entity nametag rendering mode<br>None, Hovered, All, AllHovered, AllUnscaled
`entityshadow`|`None`|Entity shadow rendering mode<br>None, SnapToBlock, Circle, CircleAll
### Texture pack options
|Name|Default|Description|
|--|--|--|
`defaulttexpack`|`default.zip`|Filename of default texture pack
### Window options
|Name|Default|Description|
|--|--|--|
`window-width`|`854`|Width of game window<br>Width must be between 0 and display width
`window-height`|`480`|Height of game window<br>Height must be between 0 and display height
`win-grab-cursor`|`false`|Whether to grab exclusive control over the cursor<br>**Only supported on Linux/BSD**
./Gui.c: Gui.Chatlines = Options_GetInt(OPT_CHATLINES, 0, 30, Gui.DefaultLines);
./Gui.c: Gui.ClickableChat = !Game_ClassicMode && Options_GetBool(OPT_CLICKABLE_CHAT, !Input_TouchMode);
./Gui.c: Gui.TabAutocomplete = !Game_ClassicMode && Options_GetBool(OPT_TAB_AUTOCOMPLETE, true);
./Gui.c: Gui.ClassicTexture = Options_GetBool(OPT_CLASSIC_GUI, true) || Game_ClassicMode;
./Gui.c: Gui.ClassicTabList = Options_GetBool(OPT_CLASSIC_TABLIST, false) || Game_ClassicMode;
./Gui.c: Gui.ClassicMenu = Options_GetBool(OPT_CLASSIC_OPTIONS, false) || Game_ClassicMode;
./Gui.c: Gui.ClassicChat = Options_GetBool(OPT_CLASSIC_CHAT, false) || Game_PureClassic;
./Gui.c: Gui.ShowFPS = Options_GetBool(OPT_SHOW_FPS, true);
./Gui.c: Gui.RawInventoryScale = Options_GetFloat(OPT_INVENTORY_SCALE, 0.25f, 5.0f, 1.0f);
./Gui.c: Gui.RawHotbarScale = Options_GetFloat(OPT_HOTBAR_SCALE, 0.25f, 5.0f, 1.0f);
./Gui.c: Gui.RawChatScale = Options_GetFloat(OPT_CHAT_SCALE, 0.25f, 5.0f, 1.0f);
./Gui.c: Gui.RawTouchScale = Options_GetFloat(OPT_TOUCH_SCALE, 0.25f, 5.0f, 1.0f);
./Gui.c: Gui._onscreenButtons = Options_GetInt(OPT_TOUCH_BUTTONS, 0, Int32_MaxValue,
./Input.c: mapping = Options_GetEnum(name.buffer, KeyBind_Defaults[i], Input_Names, INPUT_COUNT);

View File

@@ -0,0 +1,72 @@
Although ClassiCube strives to be as platform independent as possible, in some cases it will need to use system specific code
For instance:
* Texture creation for 3D graphics rendering
* Buffer allocation for audio output
* High resolution time measurement
* Window creation
For simplicity, related system specific code is grouped together as a Module (e.g. `Audio`), which can then be implemented using a backend (e.g. `WinMM`, `OpenAL`, `OpenSL ES`, etc)
#### Note: By default, ClassiCube automatically selects the recommended backends for the system. <br> It is recommended that you do *NOT* change the backends unless you know exactly what you are doing.
Some systems may provide multiple potential backends for a Module. For example on Windows:
* OpenGL could be used instead of Direct3D 9 for the 3D rendering backend
* SDL could be used instead of the native WinAPI for the window backend
TODO finish this
TODO introduction (explaining platform specific modules, and how classicube has to integrate with one of them)
There are two ways of changing the backend that gets used for the system:
1) Changing the default defines in `Core.h`
2) Using additional compilation flags to override default module backend(s)
3) Adding `-DCC_BUILD_MANUAL` to compilation flags and then manually defining all module backends via additional compilation flags
When manually compiling the source code, 1) is usually the easiest. <br>
For automated scripts compiling every single commit, 2) is the recommended approach
TODO: Move this into table
### 3D Graphics backends (`CC_GFX_BACKEND`)
* CC_GFX_BACKEND_SOFTGPU - Software rasteriser
* CC_GFX_BACKEND_D3D9 - Direct3D 9
* CC_GFX_BACKEND_D3D11 - Direct3D 11
* CC_GFX_BACKEND_GL1 - OpenGL 1.2/1.5
* CC_GFX_BACKEND_GL2 - OpenGL 2 (shaders)
The OpenGL backend can be further customised:
* CC_BUILD_GL11 (must be using CC_GFX_BACKEND_GL1)
* CC_BUILD_GLES (must be using CC_GFX_BACKEND_GL2)
### OpenGL context backends
* CC_BUILD_EGL
* CC_BUILD_WGL
### HTTP backends (`CC_NET_BACKEND`)
* CC_NET_BACKEND_BUILTIN - custom HTTP client
* CC_NET_BACKEND_LIBCURL
* CC_BUILD_CFNETWORK
### SSL backends (`CC_SSL_BACKEND`)
* CC_SSL_BACKEND_NONE
* CC_SSL_BACKEND_BEARSSL
* CC_SSL_BACKEND_SCHANNEL
### Window backends (`CC_WIN_BACKEND`)
* CC_WIN_BACKEND_TERMINAL
* CC_WIN_BACKEND_SDL2
* CC_WIN_BACKEND_SDL3
* CC_WIN_BACKEND_X11
* CC_WIN_BACKEND_WIN32
### Audio backends (`CC_AUD_BACKEND`)
* CC_AUD_BACKEND_OPENAL
* CC_AUD_BACKEND_WINMM
* CC_AUD_BACKEND_OPENSLES
### Platform backends
* CC_BUILD_POSIX
* CC_BUILD_WIN
TODO fill in rest

253
doc/plugin-dev.md Normal file
View File

@@ -0,0 +1,253 @@
This document details how to compile a basic plugin in Visual Studio, MinGW, or GCC/Clang.
To find the functions and variables available for use in plugins, look for `CC_API`/`CC_VAR` in the .h files.
[Source code of some actual plugins](https://github.com/ClassiCube/ClassiCube-Plugins/)
### Setup
You need to download and install either Visual Studio, MinGW, or GCC/Clang.
*Note: MinGW/GCC/Clang are relatively small, while Visual Studio is gigabytes in size.
If you're just trying to compile a plugin on Windows you might want to use MinGW. See main readme.*
I assume your directory is structured like this:
```
src/...
TestPlugin.c
```
Or in other words, in a directory somewhere, you have a file named `TestPlugin.c`, and then a sub-directory named `src` which contains the game's source code.
### Basic plugin
```C
#include "src/Chat.h"
#include "src/Game.h"
#include "src/String.h"
static void TestPlugin_Init(void) {
cc_string msg = String_FromConst("Hello world!");
Chat_Add(&msg);
}
int Plugin_ApiVersion = 1;
struct IGameComponent Plugin_Component = { TestPlugin_Init };
```
Here's the idea for a basic plugin that shows "Hello world" in chat when the game starts. Alas, this won't compile...
### Basic plugin boilerplate
```C
#ifdef _WIN32
#define CC_API __declspec(dllimport)
#define CC_VAR __declspec(dllimport)
#define EXPORT __declspec(dllexport)
#else
#define CC_API
#define CC_VAR
#define EXPORT __attribute__((visibility("default")))
#endif
#include "src/Chat.h"
#include "src/Game.h"
#include "src/String.h"
static void TestPlugin_Init(void) {
cc_string msg = String_FromConst("Hello world!");
Chat_Add(&msg);
}
EXPORT int Plugin_ApiVersion = 1;
EXPORT struct IGameComponent Plugin_Component = { TestPlugin_Init };
```
With this boilerplate, we're ready to compile the plugin.
All plugins require this boilerplate, so feel free to copy and paste it.
---
### Writing plugins in C++
Exported plugin functions **must** be surrounded with `extern "C"`, i.e.
```C
extern "C" {
EXPORT int Plugin_ApiVersion = 1;
EXPORT struct IGameComponent Plugin_Component = { TestPlugin_Init };
}
```
Otherwise your plugin will not load. (you'll see `error getting plugin version` in-game)
---
## Compiling
Plugin compilation instructions differs depending on the compiler and operating system
### Linux
[Compiling using gcc or clang](plugin-dev.md#using-gcc-or-clang)
[Cross compiling for Windows 32-bit](plugin-dev.md#cross-compiling-for-windows-32-bit-using-mingw-w64)
[Cross compiling for Windows 64-bit](plugin-dev.md#cross-compiling-for-windows-64-bit-using-mingw-w64)
### macOS
[Compiling using gcc or clang](plugin-dev.md#using-gcc-or-clang-1)
### Windows
[Compiling using Visual Studio](plugin-dev.md#using-visual-studio)
[Compiling using mingw-w64](plugin-dev.md#using-mingw-w64)
---
## Compiling - Linux
### Using gcc or clang
#### Compiling
`cc TestPlugin.c -o TestPlugin.so -shared -fPIC`
Then put `TestPlugin.so` into your game's `plugins` folder. Done.
### Cross compiling for Windows 32 bit using mingw-w64
#### Setup
1) Create `ClassiCube.exe` by either:
1) Compiling the game, see `Cross compiling for windows (32 bit)` in [main readme](/readme.md#cross-compiling-for-windows-32-bit)
2) Downloading 32 bit ClassiCube from https://www.classicube.net/download/#dl-win
2) Install the `mingw-w64-tools` package (if it isn't already)
3) Generate the list of exported symbols from `ClassiCube.exe` by running:
* `gendef ClassiCube.exe`
4) Create a linkable library from the exported symbols list by running:
* `i686-w64-mingw32-dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe`
TODO: also document alternate method of compiling the game using --out-implib
#### Compiling
`i686-w64-mingw32-gcc TestPlugin.c -o TestPlugin.dll -s -shared -L . -lClassiCube`
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
### Cross compiling for Windows 64 bit using mingw-w64
#### Setup
1) Create `ClassiCube.exe` by either:
1) Compiling the game, see `Cross compiling for windows (64 bit)` in [main readme](/readme.md#cross-compiling-for-windows-64-bit)
2) Downloading 64 bit ClassiCube from https://www.classicube.net/download/#dl-win
2) Install the `mingw-w64-tools` package (if it isn't already)
3) Generate the list of exported symbols from `ClassiCube.exe` by running:
* `gendef ClassiCube.exe`
4) Create a linkable library from the exported symbols list by running:
* `x86_64-w64-mingw32-dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe`
TODO: also document alternate method of compiling the game using --out-implib
#### Compiling
`x86_64-w64-mingw32-gcc TestPlugin.c -o TestPlugin.dll -s -shared -L . -lClassiCube`
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
## Compiling - macOS
### Using gcc or clang
#### Compiling
`cc TestPlugin.c -o TestPlugin.dylib -undefined dynamic_lookup`
Then put `TestPlugin.dylib` into your game's `plugins` folder. Done.
## Compiling - Windows
### Using Visual Studio
TODO more detailed when I have some more time...
#### Setup
1) Compile the game, see `Compiling - Windows > using Visual Studio` in main readme
2) Find the `ClassiCube.lib` that was generated when compiling the game. Usually it is in either `src\x64\Debug` or `src\x86\Debug`.
3) Add a new `Empty Project` to the ClassiCube solution, then add the plugin .c files to it
Note: If the plugin provides a .vcxproj file, you can skip step 2 and just open that project file instead.
#### Configuration - alternative #1
The simplest way of linking to the `.lib` file is simply adding the following code to one of the plugin's `.c` files
```C
#ifdef _MSC_VER
#ifdef _WIN64
#pragma comment(lib, "[GAME SRC FOLDER]/x64/Debug/ClassiCube.lib")
#else
#pragma comment(lib, "[GAME SRC FOLDER]/x86/Debug/ClassiCube.lib")
#endif
#endif
```
replacing `[GAME SRC FOLDER]` with the full path of `src` folder (e.g. `C:/Dev/ClassiCube/src`)
#### Configuration - alternative #2
The more complicated way of linking to the `.lib` file is to add it to the plugin's project configuration file
Right click the plugin project in the `Solution Explorer` pane, then click `Properties`
TODO: add screenshots here
TODO: may need to configure include directories
1) In `Configuration properties` -> `General`, make sure `Configuration type` is set to `Dynamic library (.DLL)`
2) In `Configuration properties` -> `Linker` -> `Input`, click the dropdown button for `Additional Dependencies`, then click `Edit`. Add the full path to `ClassiCube.lib`, then click `OK`
#### Compiling
Build the project. There should be a line in the build output that tells you where you can find the .dll file like this:
`
Project1.vcxproj -> C:\classicube-dev\testplugin\src\x64\Debug\TestPlugin.dll
`
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
### Using mingw-w64
#### Setup
1) Create `ClassiCube.exe` by either:
1) Compiling the game, see `Compiling for windows (MinGW-w64)` in [main readme](/readme.md#using-mingw-w64)
2) Downloading ClassiCube from https://www.classicube.net/download/#dl-win
2) Generate the list of exported symbols in `ClassiCube.exe` by running:
* `gendef ClassiCube.exe`
3) Create a linkable library from the exported symbols list by running:
* `dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe`
#### Compiling
`gcc TestPlugin.c -o TestPlugin.dll -s -shared -L . -lClassiCube`
Then put `TestPlugin.dll` into your game's `plugins` folder. Done.
## Notes for compiling for Windows
### Ensuring your plugin works when the ClassiCube exe isn't named ClassiCube.exe
If you follow the prior compilation instructions, the compiled DLL will have a runtime dependancy on `ClassiCube.exe`
However, this means that if the executable is e.g. named `ClassiCube (2).exe` instead. the plugin DLL will fail to load
To avoid this problem, you must
1) Stop linking to `ClassiCube` (e.g. for `MinGW`, remove the ` -L . -lClassiCube`)
2) Load all functions and variables exported from ClassiCube via `GetProcAddress` instead
This is somewhat tedious to do - see [here](https://github.com/ClassiCube/ClassiCube-Plugins/) for some examples of plugins which do this
#### Compiling ultra small plugin DLLs - MinGW
If you **ONLY** use code from the game (no external libraries and no C standard library functions):
* You can add `-nostartfiles -Wl,--entry=0` to the compile flags to reduce the DLL size (e.g from 11 to 4 kb)
This isn't necessary to do though, and plugin DLLs work completely fine without doing this.

93
doc/portability.md Normal file
View File

@@ -0,0 +1,93 @@
Although most of the code is platform-independent, some per-platform functionality is required.
By default `Core.h` tries to automatically define appropriate backends for your system. Define ```CC_BUILD_MANUAL``` to disable this.
Note: Updating doesn't work properly in Windows 95 or Windows 98
## Before you start
* IEEE floating-point support is required. (Can be emulated in software, but will affect performance)
* The `int` data type must be 32-bits.
* 32-bit addressing (or more) is required.
* Support for 8/16/32/64 integer types is required. (your compiler must support 64-bit arithmetic)
* At least around 2 MB of RAM is required at a minimum
* At least 128 kb for main thread stack size
In summary, the codebase can theroetically be ported to any modern-ish hardware, but not stuff like a UNIVAC machine, the SuperFX chip on the SNES, or an 8-bit microcontroller.
## Porting
Listed below are the requirements for implementing each platform-dependent file.<br>
When porting to other platforms, you should try to leverage existing backends when possible.<br>
Only cross platform backends are listed below.
### Platform
General platform specific functionality.
- Get exe path, start/exit process, open url in browser
- Dynamic library management
- Allocate, free, copy, set memory
- Current system time, stopwatch time
- File I/O, Directory I/O, Socket I/O
- Threading, signalable wait, mutex
- Drawing/measuring native font
- Native font text drawing and measuring
- Encrypt/decrypt data, getting command line args
Define:
- ```CC_BUILD_POSIX``` - Use posix API
posix note: Some functions are not covered. (stopwatch, getting exe path, open url in browser)
These must still be implemented for each operating system
### Window
Create a window, show a dialog window, set window contents, keyboard/mouse input
Also monitor size, clipboard, cursor, raw relative mouse movement (optional)
Define:
- ```DEFAULT_WIN_BACKEND CC_WIN_BACKEND_X11 ``` - Use X11/XLib (unix-ish) (glX)
- ```DEFAULT_WIN_BACKEND CC_WIN_BACKEND_SDL2``` - Use SDL2 library (SDL2)
If using OpenGL, also OpenGL context management
### Logger
Dump registers and backtrace, log unhandled errors (e.g. invalid memory read)
Define:
- ```CC_BUILD_POSIX``` - use POSIX api
posix note: Register access is highly dependent on OS and architecture.
(e.g. Linux uses &r.gregs[REG_EAX] while FreeBSD uses &r.mc_eax)
### Audio
Play multiple audio streams with varying sample rates
Define:
- ```DEFAULT_AUD_BACKEND CC_AUD_BACKEND_OPENAL``` - use OpenAL
- ```CC_BUILD_NOAUDIO``` - stub audio implementation (silent)
### 3D Graphics
Texturing, depth buffer, alpha, etc (See Graphics.h for full list)
Define:
- ```DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL1``` - Use legacy OpenGL (1.5/1.2 + ARB_VERTEX_BUFFER_OBJECT)
- ```CC_BUILD_GL11``` - Use OpenGL 1.1 features only
- ```DEFAULT_GFX_BACKEND CC_GFX_BACKEND_GL2``` - Use modern OpenGL shaders
- ```CC_BUILD_GLES``` - Makes these shaders compatible with OpenGL ES
- ```DEFAULT_GFX_BACKEND CC_GFX_BACKEND_SOFTGPU``` - Use built in software rasteriser
### HTTP
HTTP, HTTPS, and setting request/getting response headers
Define:
- ```DEFAULT_NET_BACKEND CC_NET_BACKEND_BUILTIN``` - use built in simple HTTP backend
- ```DEFAULT_NET_BACKEND CC_NET_BACKEND_LIBCURL``` - use libcurl for HTTP
Supporting connection reuse is highly recommended. (but not required)
### SSL
SSL and TLS support, plus basic certificate validation
Define:
- ```DEFAULT_SSL_BACKEND CC_SSL_BACKEND_BEARSSL``` - use BearSSL for SSL/TLS

12
doc/readme.md Normal file
View File

@@ -0,0 +1,12 @@
This folder contains general information relating to the game's source code.
|File|Description|
|--------|-------|
|compile-fixes.md | Steps on how to fix some common compilation errors |
|hosting-flask.md | Example website that hosts the web client using [Flask](https://flask.palletsprojects.com/)|
|hosting-webclient.md | Explains how to integrate the web client into your own website |
|modules.md | Provides a summary about the modules that constitute the game's code|
|plugin-dev.md | Explains how to compile a simple plugin for the game |
|portability.md | Provides information about porting this game to other platforms |
|style.md | Explains the style guidelines that the source code generally follows |
|strings.md | Provides details about the custom string type used by this game |

42
doc/sound-credits.md Normal file
View File

@@ -0,0 +1,42 @@
## Sources
https://old.reddit.com/r/Minecraft/comments/3zxucv/where_did_the_sound_in_minecraft_come_from/
https://web.archive.org/web/20100830062601/http://minecraft.net/credits.jsp
https://web.archive.org/web/20100124101348/http://www.freesound.org/usersAttribution.php?id=1045860&format=html
https://web.archive.org/web/20100613143900/http://www.freesound.org/usersAttribution.php?id=584268
https://freesound.org/people/C418/downloaded_sounds/?page=7#sound
## Sounds
**dig/step_grass1** - grass1.wav by Snoman
* https://freesound.org/people/Snoman/sounds/9904/
**dig/step_grass2** - grass2.wav by Snoman
* https://freesound.org/people/Snoman/sounds/9905/
**dig/step_grass3** - grass3.wav by Snoman
* https://freesound.org/people/Snoman/sounds/9906/
**dig/step_grass4** - grass4.wav by Snoman
* https://freesound.org/people/Snoman/sounds/9907/
**dig_glass1** - glass shatter.wav by datasoundsample
* https://freesound.org/people/datasoundsample/sounds/41348/
**dig_glass2** - gb12.aif by lsprice
* http://www.freesound.org/samplesViewSingle.php?id=88808/
**dig_glass3** - bm_Glass_Break.wav by cmusounddesign
* https://freesound.org/people/cmusounddesign/sounds/71947/
**dig/step_gravel1** - gravel walking.aif by tigersound
* https://freesound.org/people/tigersound/sounds/15562/
**dig/step_gravel2** - gravel walking.aif by tigersound
* https://freesound.org/people/tigersound/sounds/15562/
**dig/step_gravel3** - gravel walking.aif by tigersound
* https://freesound.org/people/tigersound/sounds/15562/
**dig/step_gravel4** - gravel walking.aif by tigersound
* https://freesound.org/people/tigersound/sounds/15562/

329
doc/strings.md Normal file
View File

@@ -0,0 +1,329 @@
## Introduction
ClassiCube uses a custom string type rather than the standard C `char*` string in most places
ClassiCube strings (`cc_string`) are a struct with the following fields:
- `buffer` -> Pointer to 8 bit characters (unsigned [code page 437 indices](https://en.wikipedia.org/wiki/Code_page_437#Character_set))
- `length` -> Number of characters currently used
- `capacity` -> Maximum number of characters (i.e buffer size)
Note: This means **STRINGS MAY NOT BE NULL TERMINATED** (and are not in most cases)
You should also read the **Strings** section in the [style guide](/doc/style.md)
## Memory management
Some general guidelines to keep in mind when it comes to `cc_string` strings:
- String buffers can be allocated on either the stack or heap<br>
(i.e. make sure you don't return strings that are using stack allocated buffers)
- Strings are fixed capacity (strings do not grow when length reaches capcity)<br>
(i.e. make sure you allocate a large enough buffer upfront)
- Strings are not garbage collected or reference counted<br>
(i.e. you are responsible for managing the lifetime of strings)
## Usage examples
Initialisating a string from readonly text:
```C
cc_string str = String_FromConst("ABC");
```
Initialising a string from temporary memory on the stack:
```C
// str will be able to store at most 200 characters in it
char strBuffer[200];
cc_string str = String_FromArray(strBuffer);
```
Initialising a string from persistent memory on the heap:
```C
// str will be able to store at most 200 characters in it
char* str = Mem_Alloc(1, 200, "String buffer");
cc_string str = String_Init(str, 0, 200);
```
# Converting to/from other string representations
## C String conversion
### C string -> cc_string
Creating a `cc_string` string from a C string is straightforward:
#### From a constant C string
```C
void Example(void) {
cc_string str = String_FromConst("test");
}
```
#### From a C string
```C
void Example(const char* c_str) {
cc_string str = String_FromReadonly(c_str);
}
```
Note: `String_FromReadonly` can also be used with constant C strings, it's just a bit slower
#### From a C fixed size string
```C
struct Something { int value; char name[50]; };
void Example(struct Something* some) {
cc_string str = String_FromRawArray(some->name);
}
```
### cc_string -> C string
The `buffer` field **should not** be treated as a C string, because `cc_string` strings **MAY NOT BE NULL TERMINATED**
The general way to achieve this is to
1. Initialise `capacity` with 1 less than actual buffer size (e.g. use `String_InitArray_NT` instead of `String_InitArray`)
2. Perform various operations on the `cc_string` string
3. Add null terminator to end (i.e. `buffer[length]` = '\0';
4. Use `buffer` as a C string now
For example:
```C
void PrintInt(int value) {
cc_string str; char strBuffer[128];
String_InitArray_NT(str, strBuffer);
String_AppendInt(&str, value);
str.buffer[str.length] = '\0';
puts(str.buffer);
}
```
## OS String conversion
`cc_string` strings cannot be directly used as arguments for operating system functions and must be converted first.
The following functions are provided to convert `cc_string` strings into operating system specific encoded strings:
### cc_string -> Windows string
`Platform_EncodeString` converts a `cc_string` into a null terminated `WCHAR` and `CHAR` string
#### Example
```C
void SetWorkingDir(cc_string* title) {
cc_winstring str;
Platform_EncodeUtf16(&str, title);
SetCurrentDirectoryW(str.uni);
// it's recommended that you DON'T use the ansi format whenever possible
//SetCurrentDirectoryA(str.ansi);
}
```
### cc_string -> UTF8 string
`String_EncodeUtf8` converts a `cc_string` into a null terminated UTF8-encoded `char*` string
#### Example
```C
void SetWorkingDir(cc_string* title) {
char buffer[NATIVE_STR_LEN];
String_EncodeUtf8(buffer, title);
chdir(buffer);
}
```
# API
I'm lazy so I will just link to [String.h](/src/String.h)
If you'd rather I provided a more detailed reference here, please let me know.
TODO
# Comparisons to other string implementations
## C comparison
A rough mapping of C string API to ClassiCube's string API:
```
atof -> Convert_ParseFloat
strtof -> Convert_ParseFloat
atoi -> Convert_ParseInt
strtoi -> Convert_ParseInt
strcat -> String_AppendConst/String_AppendString
strcpy -> String_Copy
strtok -> String_UNSAFE_Split
strlen -> str.length
strcmp -> String_Equals/String_Compare
strchr -> String_IndexOf
strrchr -> String_LastIndexOf
strstr -> String_IndexOfConst
sprintf -> String_Format1/2/3/4
%d -> %i
%04d -> %p4
%i -> %i
%c -> %r
%.4f -> %f4
%s -> %s (cc_string)
%s -> %c (char*)
%x -> %h
```
## C# comparison
A rough mapping of C# string API to ClassiCube's string API:
```
byte.Parse -> Convert_ParseUInt8
ushort.Parse -> Convert_ParseUInt16
float.Parse -> Convert_ParseFloat
int.Parse -> Convert_ParseInt
ulong.Parse -> Convert_ParseUInt64
bool.Parse -> Convert_ParseBool
a += "X"; -> String_AppendString
b = a; -> String_Copy
string.Insert -> String_InsertAt
string.Remove -> String_DeleteAt
string.Substring -> String_UNSAFE_Substring/String_UNSAFE_SubstringAt
string.Split -> String_UNSAFE_Split/String_UNSAFE_SplitBy
string.TrimStart -> String_UNSAFE_TrimStart
string.TrimEnd -> String_UNSAFE_TrimEnd
a.Length -> str.length
a == b -> String_Equals
string.Equals -> String_CaslessEquals (StringComparison.OrdinalIgnoreCase)
string.IndexOf -> String_IndexOf/String_IndexOfConst
string.LastIndexOf -> String_LastIndexOf
string.StartsWith -> String_CaselessStarts (StringComparison.OrdinalIgnoreCase)
string.EndsWith -> String_CaselessEnds (StringComparison.OrdinalIgnoreCase)
string.CompareTo -> String_Compare
string.Format -> String_Format1/2/3/4
```
*Note: I modelled cc_string after C# strings, hence the similar function names*
## C++ comparison
A rough mapping of C++ std::string API to ClassiCube's string API:
```
std::stof -> Convert_ParseFloat
std::stoi -> Convert_ParseInt
std::stoul -> Convert_ParseUInt64
string::append -> String_AppendString/String_AppendConst
b = a; -> String_Copy
string::insert -> String_InsertAt
string::erase -> String_DeleteAt
string::substr -> String_UNSAFE_Substring/String_UNSAFE_SubstringAt
string::length -> str.length
a == b -> String_Equals
string::find -> String_IndexOf/String_IndexOfConst
string::rfind -> String_LastIndexOf
string::compare -> String_Compare
std::sprintf -> String_Format1/2/3/4
```
# Detailed lifetime examples
Managing the lifetime of strings is important, as not properly managing them can cause issues.
For example, consider the following function:
```C
const cc_string* GetString(void);
void PrintSomething(void) {
cc_string* str = GetString();
// .. other code ..
Chat_Add(str);
}
```
Without knowing the lifetime of the string returned from `GetString`, using it might either:
* Work just fine
* Sometimes work fine
* Cause a subtle issue
* Cause a major problem
ptodo rearrange
### Constant string return example
```C
const cc_string* GetString(void) {
static cc_string str = String_FromConst("ABC");
return &str;
}
```
This will work fine - as long as the caller does not modify the returned string at all
### Stack allocated string return example
```C
const cc_string* GetString(void) {
char strBuffer[1024];
cc_string str = String_FromArray(strBuffer);
String_AppendConst(&str, "ABC");
return &str;
}
```
This will **almost certainly cause problems** - after `GetString` returns, the contents of both `str` and `strBuffer` may be changed to arbitary values (as once `GetString` returns, their contents are then eligible to be overwritten by other stack allocated variables)
As a general rule, you should **NEVER** return a string allocated on the stack
### Dynamically allocated string return example
```C
const cc_string* GetString(void) {
char* buffer = Mem_Alloc(1024, 1, "string buffer");
cc_string* str = Mem_Alloc(1, sizeof(cc_string), "string");
*str = String_Init(buffer, 0, 1024);
String_AppendConst(str, "ABC");
return str;
}
```
This will work fine - however, now you also need to remember to `Mem_Free` both the string and its buffer to avoid a memory leak
As a general rule, you should avoid returning a dynamically allocated string
### UNSAFE mutable string return example
```C
char global_buffer[1024];
cc_string global_str = String_FromArray(global_buffer);
const cc_string* GetString(void) {
return &global_str;
}
```
Depending on what functions are called in-between `GetString` and `Chat_Add`, `global_str` or its contents may be modified - which can result in an unexpected value being displayed in chat
This potential issue is not just theoretical - it has actually resulted in several real bugs in ClassiCube itself
As a general rule, for unsafe functions returning a string that may be mutated behind your back, you should try to maintain a reference to the string for as short of time as possible
### Reducing string lifetime issues
In general, for functions that produce strings, you should try to leave the responsibility of managing the string's lifetime up to the calling function to avoid these pitfalls
The example from before could instead be rewritten like so:
```C
void GetString(cc_string* str);
void PrintSomething(void) {
char strBuffer[256];
cc_string str = String_InitArray(strBuffer);
GetString(&str);
// .. other code ..
Chat_Add(&str);
}
```

34
doc/style.md Normal file
View File

@@ -0,0 +1,34 @@
### Guidelines
* Code should be C89 compatible and compilable as C++.
* Each .c file should represent a module. (see architecture.md for more details)
* Public functions and variables should be prefixed by module to avoid name collisions. (e.g. `Game_Reset`)
* Private functions should be named using pascal case. Prefixing module is optional - do it when it makes sense.
* Private variables don't really have a consistent style.
### Types
* Explicit integer size typedefs are provided in `Core.h` for when needed. Otherwise just use int.
* A few common simple structs are typedef-ed, but are rarely otherwise.
* `cc_bool` is an alias for 8 bit unsigned integer
* `PackedCol` field order differs depending on the underlying 3D graphics API
Note: The explicit integer size typedefs may not have been defined if you aren't compiling using GCC/Clang/MSVC, so for other compilers you may need to add them into `Core.h`
### Strings
A custom string type (`cc_string`) is used rather than `char*` strings in most places (see [strings](strings.md) page for more details)
*Note: Several functions will take raw `char*` for performance, but this is not encouraged*
#### String arguments
String arguments are annotated to indicate storage and readonly requirements. These are:
- `const cc_string*` - String is not modified at all
- `cc_string*` - Characters in string may be modified
- `STRING_REF` - Macro annotation indicating a **reference is kept to the characters**
To make it extra clear, functions with `STRING_REF` arguments usually also have `_UNSAFE_` as part of their name.
For example, consider the function `cc_string Substring_UNSAFE(STRING_REF const cc_string* str, length)`
The *input string* is not modified at all. However, the characters of the *returned string* points to the characters of the *input string*, so modifying the characters in the *input string* also modifies the *returned string*.
In general, use of `const cc_string*` is preferred when possible, and `STRING_REF` as little as possible.

350
license.txt Normal file
View File

@@ -0,0 +1,350 @@
Copyright (c) 2014 - 2024, UnknownShadow200
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or other
materials provided with the distribution.
3. Neither the name of ClassiCube nor the names of its contributors may be
used to endorse or promote products derived from this software without specific prior
written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Other function licenses
=======================
Ray-box intersection algorithm comes from:
"An efficient and robust ray-box intersection algorithm", Williams, Barrus, Morley & Shirley, Journal of Graphics Tools, 2005"
C++ source at http://www.cs.utah.edu/~awilliam/box/ does not appear to have an attached license.
Cell traversal of rays based on code I found that was in turn from http://www.xnawiki.com/index.php/Voxel_traversal
The archived about page (http://web.archive.org/web/20090412065116/http://www.xnawiki.com/index.php/XNAWiki:About) states
that "All code found on the wiki is considered public domain".
Frustum culling was based on the code from http://www.crownandcutlass.com/features/technicaldetails/frustum.html,
which is in turn archived from (now defunct) http://www.markmorley.com/
"This page and its contents are Copyright 2000 by Mark Morley
Unless otherwise noted, you may use any and all code examples provided herein in any way you want."
OpenTK license
===============
Copyright (c) 2006 - 2010 The Open Toolkit library.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
OpenTK.Platform.Windows and OpenTK.Platform.X11 include portions of the Mono class library.
These portions are covered by the following license:
Copyright (c) 2004 Novell, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Emscripten license
==============================================================================
Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
==============================================================================
Copyright (c) 2010-2014 Emscripten authors, see AUTHORS file.
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal with the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimers.
Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimers
in the documentation and/or other materials provided with the
distribution.
Neither the names of Mozilla,
nor the names of its contributors may be used to endorse
or promote products derived from this Software without specific prior
written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
==============================================================================
BearSSL license
==============================================================================
Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
==============================================================================
FreeType license
==================
The FreeType Project LICENSE
----------------------------
2006-Jan-27
Copyright 1996-2002, 2006 by
David Turner, Robert Wilhelm, and Werner Lemberg
Introduction
============
The FreeType Project is distributed in several archive packages;
some of them may contain, in addition to the FreeType font engine,
various tools and contributions which rely on, or relate to, the
FreeType Project.
This license applies to all files found in such packages, and
which do not fall under their own explicit license. The license
affects thus the FreeType font engine, the test programs,
documentation and makefiles, at the very least.
This license was inspired by the BSD, Artistic, and IJG
(Independent JPEG Group) licenses, which all encourage inclusion
and use of free software in commercial and freeware products
alike. As a consequence, its main points are that:
o We don't promise that this software works. However, we will be
interested in any kind of bug reports. (`as is' distribution)
o You can use this software for whatever you want, in parts or
full form, without having to pay us. (`royalty-free' usage)
o You may not pretend that you wrote this software. If you use
it, or only parts of it, in a program, you must acknowledge
somewhere in your documentation that you have used the
FreeType code. (`credits')
We specifically permit and encourage the inclusion of this
software, with or without modifications, in commercial products.
We disclaim all warranties covering The FreeType Project and
assume no liability related to The FreeType Project.
Finally, many people asked us for a preferred form for a
credit/disclaimer to use in compliance with this license. We thus
encourage you to use the following text:
"""
Portions of this software are copyright © <year> The FreeType
Project (www.freetype.org). All rights reserved.
"""
Please replace <year> with the value from the FreeType version you
actually use.
Legal Terms
===========
0. Definitions
--------------
Throughout this license, the terms `package', `FreeType Project',
and `FreeType archive' refer to the set of files originally
distributed by the authors (David Turner, Robert Wilhelm, and
Werner Lemberg) as the `FreeType Project', be they named as alpha,
beta or final release.
`You' refers to the licensee, or person using the project, where
`using' is a generic term including compiling the project's source
code as well as linking it to form a `program' or `executable'.
This program is referred to as `a program using the FreeType
engine'.
This license applies to all files distributed in the original
FreeType Project, including all source code, binaries and
documentation, unless otherwise stated in the file in its
original, unmodified form as distributed in the original archive.
If you are unsure whether or not a particular file is covered by
this license, you must contact us to verify this.
The FreeType Project is copyright (C) 1996-2000 by David Turner,
Robert Wilhelm, and Werner Lemberg. All rights reserved except as
specified below.
1. No Warranty
--------------
THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO
USE, OF THE FREETYPE PROJECT.
2. Redistribution
-----------------
This license grants a worldwide, royalty-free, perpetual and
irrevocable right and license to use, execute, perform, compile,
display, copy, create derivative works of, distribute and
sublicense the FreeType Project (in both source and object code
forms) and derivative works thereof for any purpose; and to
authorize others to exercise some or all of the rights granted
herein, subject to the following conditions:
o Redistribution of source code must retain this license file
(`FTL.TXT') unaltered; any additions, deletions or changes to
the original files must be clearly indicated in accompanying
documentation. The copyright notices of the unaltered,
original files must be preserved in all copies of source
files.
o Redistribution in binary form must provide a disclaimer that
states that the software is based in part of the work of the
FreeType Team, in the distribution documentation. We also
encourage you to put an URL to the FreeType web page in your
documentation, though this isn't mandatory.
These conditions apply to any software derived from or based on
the FreeType Project, not just the unmodified files. If you use
our work, you must acknowledge us. However, no fee need be paid
to us.
3. Advertising
--------------
Neither the FreeType authors and contributors nor you shall use
the name of the other for commercial, advertising, or promotional
purposes without specific prior written permission.
We suggest, but do not require, that you use one or more of the
following phrases to refer to this software in your documentation
or advertising materials: `FreeType Project', `FreeType Engine',
`FreeType library', or `FreeType Distribution'.
As you have not signed this license, you are not required to
accept it. However, as the FreeType Project is copyrighted
material, only this license, or another one contracted with the
authors, grants you the right to use, distribute, and modify it.
Therefore, by using, distributing, or modifying the FreeType
Project, you indicate that you understand and accept all the terms
of this license.
4. Contacts
-----------
There are two mailing lists related to FreeType:
o freetype@nongnu.org
Discusses general use and applications of FreeType, as well as
future and wanted additions to the library and distribution.
If you are looking for support, start in this list if you
haven't found anything to help you in the documentation.
o freetype-devel@nongnu.org
Discusses bugs, as well as engine internals, design issues,
specific licenses, porting, etc.
Our home page can be found at
https://www.freetype.org
--- end of FTL.TXT ---

131
misc/32x/32x.h Normal file
View File

@@ -0,0 +1,131 @@
#ifndef __32X_H__
#define __32X_H__
/* Create a 5:5:5 RGB color */
#define COLOR(r,g,b) (((r)&0x1F)|((g)&0x1F)<<5|((b)&0x1F)<<10)
#define MARS_CRAM (*(volatile unsigned short *)0x20004200)
#define MARS_FRAMEBUFFER (*(volatile unsigned short *)0x24000000)
#define MARS_OVERWRITE_IMG (*(volatile unsigned short *)0x24020000)
#define MARS_SDRAM (*(volatile unsigned short *)0x26000000)
#define MARS_SYS_INTMSK (*(volatile unsigned short *)0x20004000)
#define MARS_SYS_DMACTR (*(volatile unsigned short *)0x20004006)
#define MARS_SYS_DMASAR (*(volatile unsigned long *)0x20004008)
#define MARS_SYS_DMADAR (*(volatile unsigned long *)0x2000400C)
#define MARS_SYS_DMALEN (*(volatile unsigned short *)0x20004010)
#define MARS_SYS_DMAFIFO (*(volatile unsigned short *)0x20004012)
#define MARS_SYS_VRESI_CLR (*(volatile unsigned short *)0x20004014)
#define MARS_SYS_VINT_CLR (*(volatile unsigned short *)0x20004016)
#define MARS_SYS_HINT_CLR (*(volatile unsigned short *)0x20004018)
#define MARS_SYS_CMDI_CLR (*(volatile unsigned short *)0x2000401A)
#define MARS_SYS_PWMI_CLR (*(volatile unsigned short *)0x2000401C)
#define MARS_SYS_COMM0 (*(volatile unsigned short *)0x20004020) /* Master SH2 communication */
#define MARS_SYS_COMM2 (*(volatile unsigned short *)0x20004022)
#define MARS_SYS_COMM4 (*(volatile unsigned short *)0x20004024) /* Slave SH2 communication */
#define MARS_SYS_COMM6 (*(volatile unsigned short *)0x20004026)
#define MARS_SYS_COMM8 (*(volatile unsigned short *)0x20004028) /* controller 1 current value */
#define MARS_SYS_COMM10 (*(volatile unsigned short *)0x2000402A) /* controller 2 current value */
#define MARS_SYS_COMM12 (*(volatile unsigned long *)0x2000402C) /* vcount current value */
#define MARS_PWM_CTRL (*(volatile unsigned short *)0x20004030)
#define MARS_PWM_CYCLE (*(volatile unsigned short *)0x20004032)
#define MARS_PWM_LEFT (*(volatile unsigned short *)0x20004034)
#define MARS_PWM_RIGHT (*(volatile unsigned short *)0x20004036)
#define MARS_PWM_MONO (*(volatile unsigned short *)0x20004038)
#define MARS_VDP_DISPMODE (*(volatile unsigned short *)0x20004100)
#define MARS_VDP_FILLEN (*(volatile unsigned short *)0x20004104)
#define MARS_VDP_FILADR (*(volatile unsigned short *)0x20004106)
#define MARS_VDP_FILDAT (*(volatile unsigned short *)0x20004108)
#define MARS_VDP_FBCTL (*(volatile unsigned short *)0x2000410A)
#define MARS_SH2_ACCESS_VDP 0x8000
#define MARS_68K_ACCESS_VDP 0x0000
#define MARS_PAL_FORMAT 0x0000
#define MARS_NTSC_FORMAT 0x8000
#define MARS_VDP_PRIO_68K 0x0000
#define MARS_VDP_PRIO_32X 0x0080
#define MARS_224_LINES 0x0000
#define MARS_240_LINES 0x0040
#define MARS_VDP_MODE_OFF 0x0000
#define MARS_VDP_MODE_256 0x0001
#define MARS_VDP_MODE_32K 0x0002
#define MARS_VDP_MODE_RLE 0x0003
#define MARS_VDP_VBLK 0x8000
#define MARS_VDP_HBLK 0x4000
#define MARS_VDP_PEN 0x2000
#define MARS_VDP_FEN 0x0002
#define MARS_VDP_FS 0x0001
#define SH2_CCTL_CP 0x10
#define SH2_CCTL_TW 0x08
#define SH2_CCTL_CE 0x01
#define SH2_FRT_TIER (*(volatile unsigned char *)0xFFFFFE10)
#define SH2_FRT_FTCSR (*(volatile unsigned char *)0xFFFFFE11)
#define SH2_FRT_FRCH (*(volatile unsigned char *)0xFFFFFE12)
#define SH2_FRT_FRCL (*(volatile unsigned char *)0xFFFFFE13)
#define SH2_FRT_OCRH (*(volatile unsigned char *)0xFFFFFE14)
#define SH2_FRT_OCRL (*(volatile unsigned char *)0xFFFFFE15)
#define SH2_FRT_TCR (*(volatile unsigned char *)0xFFFFFE16)
#define SH2_FRT_TOCR (*(volatile unsigned char *)0xFFFFFE17)
#define SH2_FRT_ICRH (*(volatile unsigned char *)0xFFFFFE18)
#define SH2_FRT_ICRL (*(volatile unsigned char *)0xFFFFFE19)
#define SH2_DMA_SAR0 (*(volatile unsigned long *)0xFFFFFF80)
#define SH2_DMA_DAR0 (*(volatile unsigned long *)0xFFFFFF84)
#define SH2_DMA_TCR0 (*(volatile unsigned long *)0xFFFFFF88)
#define SH2_DMA_CHCR0 (*(volatile unsigned long *)0xFFFFFF8C)
#define SH2_DMA_VCR0 (*(volatile unsigned long *)0xFFFFFFA0)
#define SH2_DMA_DRCR0 (*(volatile unsigned char *)0xFFFFFE71)
#define SH2_DMA_SAR1 (*(volatile unsigned long *)0xFFFFFF90)
#define SH2_DMA_DAR1 (*(volatile unsigned long *)0xFFFFFF94)
#define SH2_DMA_TCR1 (*(volatile unsigned long *)0xFFFFFF98)
#define SH2_DMA_CHCR1 (*(volatile unsigned long *)0xFFFFFF9C)
#define SH2_DMA_VCR1 (*(volatile unsigned long *)0xFFFFFFA8)
#define SH2_DMA_DRCR1 (*(volatile unsigned char *)0xFFFFFE72)
#define SH2_DMA_DMAOR (*(volatile unsigned long *)0xFFFFFFB0)
#define SH2_INT_IPRA (*(volatile unsigned short *)0xFFFFFEE2)
#define SEGA_CTRL_UP 0x0001
#define SEGA_CTRL_DOWN 0x0002
#define SEGA_CTRL_LEFT 0x0004
#define SEGA_CTRL_RIGHT 0x0008
#define SEGA_CTRL_B 0x0010
#define SEGA_CTRL_C 0x0020
#define SEGA_CTRL_A 0x0040
#define SEGA_CTRL_START 0x0080
#define SEGA_CTRL_Z 0x0100
#define SEGA_CTRL_Y 0x0200
#define SEGA_CTRL_X 0x0400
#define SEGA_CTRL_MODE 0x0800
#define SEGA_CTRL_TYPE 0xF000
#define SEGA_CTRL_THREE 0x0000
#define SEGA_CTRL_SIX 0x1000
#define SEGA_CTRL_NONE 0xF000
#ifdef __cplusplus
extern "C" {
#endif
/* global functions in sh2_crt0.s */
extern void fast_memcpy(void *dst, void *src, int len);
extern void CacheControl(int mode);
extern void CacheClearLine(void* ptr);
extern void ScreenStretch(int src, int width, int height, int interp);
#ifdef __cplusplus
}
#endif
#endif

109
misc/32x/Makefile Normal file
View File

@@ -0,0 +1,109 @@
ifdef $(GENDEV)
ROOTDIR = $(GENDEV)
else
ROOTDIR = /opt/toolchains/sega
endif
#---------------------------------------------------------------------------------
# Configurable options
#---------------------------------------------------------------------------------
TARGET = ClassiCube-32x
BUILD_DIR = build/32x
SOURCE_DIRS = src src/32x misc/32x
#---------------------------------------------------------------------------------
# Code generation
#---------------------------------------------------------------------------------
C_FILES = $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))
S_FILES = misc/32x/sh2_crt0.s
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.s=%.o)))
LDSCRIPTSDIR = $(ROOTDIR)/ldscripts
LIBS = $(LIBPATH) -lc -lgcc -lgcc-Os-4-200 -lnosys
LIBPATH = -L$(ROOTDIR)/sh-elf/lib -L$(ROOTDIR)/sh-elf/lib/gcc/sh-elf/4.6.2 -L$(ROOTDIR)/sh-elf/sh-elf/lib
INCPATH = -I$(ROOTDIR)/sh-elf/include -I$(ROOTDIR)/sh-elf/sh-elf/include
SHCCFLAGS = -m2 -mb -Ofast -Wall -g -c -fomit-frame-pointer -DPLAT_32X -ffunction-sections -fdata-sections
SHHWFLAGS = -m2 -mb -O1 -Wall -g -c -fomit-frame-pointer
SHLDFLAGS = -T $(LDSCRIPTSDIR)/mars.ld -nostdlib -Wl,--gc-sections
SHASFLAGS = --big
MDLDFLAGS = -T $(LDSCRIPTSDIR)/md.ld --oformat binary
MDASFLAGS = -m68000 --register-prefix-optional
SHPREFIX = $(ROOTDIR)/sh-elf/bin/sh-elf-
SHCC = $(SHPREFIX)gcc
SHAS = $(SHPREFIX)as
SHLD = $(SHPREFIX)ld
SHOBJC = $(SHPREFIX)objcopy
MDPREFIX = $(ROOTDIR)/m68k-elf/bin/m68k-elf-
MDAS = $(MDPREFIX)as
MDLD = $(MDPREFIX)ld
# Dependency tracking
DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.d
DEPFILES := $(OBJS:%.o=%.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all: $(BUILD_DIR) $(BUILD_DIR)/m68k_crt0.bin $(BUILD_DIR)/m68k_crt1.bin $(TARGET).bin
clean:
rm -f $(BUILD_DIR)/*.o $(BUILD_DIR)/*.bin $(TARGET).bin $(TARGET).elf
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
#---------------------------------------------------------------------------------
# binary generation
#---------------------------------------------------------------------------------
$(TARGET).bin: $(TARGET).elf
$(SHOBJC) -O binary $< $(BUILD_DIR)/temp.bin
dd if=$(BUILD_DIR)/temp.bin of=$@ bs=64K conv=sync
$(TARGET).elf: $(OBJS)
$(SHCC) $(SHLDFLAGS) $(OBJS) $(LIBS) -o $(TARGET).elf
$(BUILD_DIR)/m68k_crt0.o: misc/32x/m68k_crt0.s
$(MDAS) $(MDASFLAGS) $< -o $@
$(BUILD_DIR)/m68k_crt0.bin: $(BUILD_DIR)/m68k_crt0.o
$(MDLD) $(MDLDFLAGS) $< -o $@
$(BUILD_DIR)/m68k_crt1.o: misc/32x/m68k_crt1.s
$(MDAS) $(MDASFLAGS) $< -o $@
$(BUILD_DIR)/m68k_crt1.bin: $(BUILD_DIR)/m68k_crt1.o
$(MDLD) $(MDLDFLAGS) $< -o $@
#---------------------------------------------------------------------------------
# object generation
#---------------------------------------------------------------------------------
$(BUILD_DIR)/%.o: src/%.c
$(SHCC) $(SHCCFLAGS) $(INCPATH) $(DEPFLAGS) $< -o $@
$(BUILD_DIR)/%.o: src/32x/%.c
$(SHCC) $(SHCCFLAGS) $(INCPATH) $(DEPFLAGS) $< -o $@
$(BUILD_DIR)/%.o: misc/32x/%.c
$(SHCC) $(SHCCFLAGS) $(INCPATH) $(DEPFLAGS) $< -o $@
$(BUILD_DIR)/%.o: misc/32x/%.s
$(SHAS) $(SHASFLAGS) $(INCPATH) $< -o $@
#---------------------------------------------------------------------------------
# Dependency tracking
#---------------------------------------------------------------------------------
$(DEPFILES):
include $(wildcard $(DEPFILES))

256
misc/32x/hw_32x.c Normal file
View File

@@ -0,0 +1,256 @@
/*
* Licensed under the BSD license
*
* debug_32x.c - Debug screen functions.
*
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
* Altered for 32X by Chilly Willy
*/
#include "32x.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
static int init = 0;
static unsigned short fgc = 0, bgc = 0;
static unsigned char fgs = 0, bgs = 0;
static unsigned short currentFB = 0;
void Hw32xSetFGColor(int s, int r, int g, int b)
{
volatile unsigned short *palette = &MARS_CRAM;
fgs = s;
fgc = COLOR(r, g, b);
palette[fgs] = fgc;
}
void Hw32xSetBGColor(int s, int r, int g, int b)
{
volatile unsigned short *palette = &MARS_CRAM;
bgs = s;
bgc = COLOR(r, g, b);
palette[bgs] = bgc;
}
void Hw32xInit(int vmode, int lineskip)
{
volatile unsigned short *frameBuffer16 = &MARS_FRAMEBUFFER;
int i;
// Wait for the SH2 to gain access to the VDP
while ((MARS_SYS_INTMSK & MARS_SH2_ACCESS_VDP) == 0) ;
if (vmode == MARS_VDP_MODE_32K)
{
// Set 16-bit direct mode, 224 lines
MARS_VDP_DISPMODE = MARS_224_LINES | MARS_VDP_MODE_32K;
// init both framebuffers
// Flip the framebuffer selection bit and wait for it to take effect
MARS_VDP_FBCTL = currentFB ^ 1;
while ((MARS_VDP_FBCTL & MARS_VDP_FS) == currentFB) ;
currentFB ^= 1;
// rewrite line table
for (i=0; i<224/(lineskip+1); i++)
{
if (lineskip)
{
int j = lineskip + 1;
while (j)
{
frameBuffer16[i*(lineskip+1) + (lineskip + 1 - j)] = i*320 + 0x100; /* word offset of line */
j--;
}
}
else
{
if (i<200)
frameBuffer16[i] = i*320 + 0x100; /* word offset of line */
else
frameBuffer16[i] = 200*320 + 0x100; /* word offset of line */
}
}
// clear screen
for (i=0x100; i<0x10000; i++)
frameBuffer16[i] = 0;
// Flip the framebuffer selection bit and wait for it to take effect
MARS_VDP_FBCTL = currentFB ^ 1;
while ((MARS_VDP_FBCTL & MARS_VDP_FS) == currentFB) ;
currentFB ^= 1;
// rewrite line table
for (i=0; i<224/(lineskip+1); i++)
{
if (lineskip)
{
int j = lineskip + 1;
while (j)
{
frameBuffer16[i*(lineskip+1) + (lineskip + 1 - j)] = i*320 + 0x100; /* word offset of line */
j--;
}
}
else
{
if (i<200)
frameBuffer16[i] = i*320 + 0x100; /* word offset of line */
else
frameBuffer16[i] = 200*320 + 0x100; /* word offset of line */
}
}
// clear screen
for (i=0x100; i<0x10000; i++)
frameBuffer16[i] = 0;
}
Hw32xSetFGColor(255,31,31,31);
Hw32xSetBGColor(0,0,0,0);
init = vmode;
}
void Hw32xScreenClear()
{
int i;
int l = (init == MARS_VDP_MODE_256) ? 320*224/2 + 0x100 : 320*200 + 0x100;
volatile unsigned short *frameBuffer16 = &MARS_FRAMEBUFFER;
// clear screen
for (i=0x100; i<l; i++)
frameBuffer16[i] = 0;
// Flip the framebuffer selection bit and wait for it to take effect
MARS_VDP_FBCTL = currentFB ^ 1;
while ((MARS_VDP_FBCTL & MARS_VDP_FS) == currentFB) ;
currentFB ^= 1;
// clear screen
for (i=0x100; i<l; i++)
frameBuffer16[i] = 0;
Hw32xSetFGColor(255,31,31,31);
Hw32xSetBGColor(0,0,0,0);
}
void Hw32xDelay(int ticks)
{
unsigned long ct = MARS_SYS_COMM12 + ticks;
while (MARS_SYS_COMM12 < ct) ;
}
void Hw32xScreenFlip(int wait)
{
// Flip the framebuffer selection bit
MARS_VDP_FBCTL = currentFB ^ 1;
if (wait)
{
while ((MARS_VDP_FBCTL & MARS_VDP_FS) == currentFB) ;
currentFB ^= 1;
}
}
void Hw32xFlipWait()
{
while ((MARS_VDP_FBCTL & MARS_VDP_FS) == currentFB) ;
currentFB ^= 1;
}
// MD Command support code ---------------------------------------------
unsigned short HwMdReadPad(int port)
{
if (port == 0)
return MARS_SYS_COMM8;
else if (port == 1)
return MARS_SYS_COMM10;
else
return SEGA_CTRL_NONE;
}
unsigned char HwMdReadSram(unsigned short offset)
{
while (MARS_SYS_COMM0) ; // wait until 68000 has responded to any earlier requests
MARS_SYS_COMM2 = offset;
MARS_SYS_COMM0 = 0x0100; // Read SRAM
while (MARS_SYS_COMM0) ;
return MARS_SYS_COMM2 & 0x00FF;
}
void HwMdWriteSram(unsigned char byte, unsigned short offset)
{
while (MARS_SYS_COMM0) ; // wait until 68000 has responded to any earlier requests
MARS_SYS_COMM2 = offset;
MARS_SYS_COMM0 = 0x0200 | byte; // Write SRAM
while (MARS_SYS_COMM0) ;
}
int HwMdReadMouse(int port)
{
unsigned int mouse1, mouse2;
while (MARS_SYS_COMM0) ; // wait until 68000 has responded to any earlier requests
MARS_SYS_COMM0 = 0x0300|port; // tells 68000 to read mouse
while (MARS_SYS_COMM0 == (0x0300|port)) ; // wait for mouse value
mouse1 = MARS_SYS_COMM0;
mouse2 = MARS_SYS_COMM2;
MARS_SYS_COMM0 = 0; // tells 68000 we got the mouse value
return (int)((mouse1 << 16) | mouse2);
}
void HwMdClearScreen(void)
{
while (MARS_SYS_COMM0) ; // wait until 68000 has responded to any earlier requests
MARS_SYS_COMM0 = 0x0400; // Clear Screen (Name Table B)
while (MARS_SYS_COMM0) ;
}
void HwMdSetOffset(unsigned short offset)
{
while (MARS_SYS_COMM0) ; // wait until 68000 has responded to any earlier requests
MARS_SYS_COMM2 = offset;
MARS_SYS_COMM0 = 0x0500; // Set offset (into either Name Table B or VRAM)
while (MARS_SYS_COMM0) ;
}
void HwMdSetNTable(unsigned short word)
{
while (MARS_SYS_COMM0) ; // wait until 68000 has responded to any earlier requests
MARS_SYS_COMM2 = word;
MARS_SYS_COMM0 = 0x0600; // Set word at offset in Name Table B
while (MARS_SYS_COMM0) ;
}
void HwMdSetVram(unsigned short word)
{
while (MARS_SYS_COMM0) ; // wait until 68000 has responded to any earlier requests
MARS_SYS_COMM2 = word;
MARS_SYS_COMM0 = 0x0700; // Set word at offset in VRAM
while (MARS_SYS_COMM0) ;
}
void HwMdPuts(char *str, int color, int x, int y)
{
HwMdSetOffset(((y<<6) | x) << 1);
while (*str)
HwMdSetNTable(((*str++ - 0x20) & 0xFF) | color);
}
void HwMdPutc(char chr, int color, int x, int y)
{
HwMdSetOffset(((y<<6) | x) << 1);
HwMdSetNTable(((chr - 0x20) & 0xFF) | color);
}
// Slave SH2 support code ----------------------------------------------
void slave(void)
{
while (1) ;
}

30
misc/32x/hw_32x.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef HW_32X_H
#define HW_32X_H
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
extern void Hw32xSetFGColor(int s, int r, int g, int b);
extern void Hw32xSetBGColor(int s, int r, int g, int b);
extern void Hw32xInit(int vmode, int lineskip);
extern int Hw32xScreenGetX();
extern int Hw32xScreenGetY();
extern void Hw32xScreenSetXY(int x, int y);
extern void Hw32xScreenClear();
extern void Hw32xDelay(int ticks);
extern void Hw32xScreenFlip(int wait);
extern void Hw32xFlipWait();
extern unsigned short HwMdReadPad(int port);
extern unsigned char HwMdReadSram(unsigned short offset);
extern void HwMdWriteSram(unsigned char byte, unsigned short offset);
extern int HwMdReadMouse(int port);
extern void HwMdClearScreen(void);
extern void HwMdSetOffset(unsigned short offset);
extern void HwMdSetNTable(unsigned short word);
extern void HwMdSetVram(unsigned short word);
extern void HwMdPuts(char *str, int color, int x, int y);
extern void HwMdPutc(char chr, int color, int x, int y);
#endif

98
misc/32x/m68k_crt0.s Normal file
View File

@@ -0,0 +1,98 @@
| SEGA 32X support code for the 68000
| by Chilly Willy
| First part of rom header
.text
| Initial exception vectors. When the console is first turned on, it is
| in MegaDrive mode. All vectors just point to the code to start up the
| Mars adapter. After the adapter is enabled, none of these vectors will
| appear as the adapter uses its own vector table to route exceptions to
| the jump table. 0x3F0 is where the 68000 starts at for the 32X.
.long 0x01000000,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
.long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
.long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
.long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
.long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
.long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
.long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
.long 0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0,0x000003F0
| Standard MegaDrive ROM header at 0x100
.ascii "SEGA 32X Example" /* SEGA must be the first four chars for TMSS */
.ascii "(C)2024 "
.ascii "ClassiCube 32X " /* export name */
.ascii " "
.ascii " "
.ascii "ClassiCube 32X " /* domestic (Japanese) name */
.ascii " "
.ascii " "
.ascii "GM MK-0000 -00"
.word 0x0000 /* checksum - not needed */
.ascii "J6 "
.long 0x00000000,0x0007FFFF /* ROM start, end */
.long 0x00FF0000,0x00FFFFFF /* RAM start, end */
.ifdef HAS_SAVE_RAM
.ascii "RA" /* External RAM */
.byte 0xF8 /* don't clear + odd bytes */
.byte 0x20 /* SRAM */
.long 0x00200001,0x0020FFFF /* SRAM start, end */
.else
.ascii " " /* no SRAM */
.endif
.ascii " "
.ascii " "
.ifdef MYTH_HOMEBREW
.ascii "MYTH3900" /* memo indicates Myth native executable */
.else
.ascii " " /* memo */
.endif
.ascii " "
.ascii " "
.ascii "F " /* enable any hardware configuration */
| Mars exception vector jump table at 0x200
jmp 0x880800.l /* reset = hot start */
jsr 0x880806.l /* EX_BusError */
jsr 0x880806.l /* EX_AddrError */
jsr 0x880806.l /* EX_IllInstr */
jsr 0x880806.l /* EX_DivByZero */
jsr 0x880806.l /* EX_CHK */
jsr 0x880806.l /* EX_TrapV */
jsr 0x880806.l /* EX_Priviledge */
jsr 0x880806.l /* EX_Trace */
jsr 0x880806.l /* EX_LineA */
jsr 0x880806.l /* EX_LineF */
.space 72 /* reserved */
jsr 0x880806.l /* EX_Spurious */
jsr 0x880806.l /* EX_Level1 */
jsr 0x880806.l /* EX_Level2 */
jsr 0x880806.l /* EX_Level3 */
jmp 0x88080C.l /* EX_Level4 HBlank */
jsr 0x880806.l /* EX_Level5 */
jmp 0x880812.l /* EX_Level6 VBlank */
jsr 0x880806.l /* EX_Level7 */
jsr 0x880806.l /* EX_Trap0 */
jsr 0x880806.l /* EX_Trap1 */
jsr 0x880806.l /* EX_Trap2 */
jsr 0x880806.l /* EX_Trap3 */
jsr 0x880806.l /* EX_Trap4 */
jsr 0x880806.l /* EX_Trap5 */
jsr 0x880806.l /* EX_Trap6 */
jsr 0x880806.l /* EX_Trap7 */
jsr 0x880806.l /* EX_Trap8 */
jsr 0x880806.l /* EX_Trap9 */
jsr 0x880806.l /* EX_TrapA */
jsr 0x880806.l /* EX_TrapB */
jsr 0x880806.l /* EX_TrapC */
jsr 0x880806.l /* EX_TrapD */
jsr 0x880806.l /* EX_TrapE */
jsr 0x880806.l /* EX_TrapF */
.space 166 /* reserved */

1846
misc/32x/m68k_crt1.s Normal file

File diff suppressed because it is too large Load Diff

802
misc/32x/sh2_crt0.s Normal file
View File

@@ -0,0 +1,802 @@
! SEGA 32X support code for SH2
! by Chilly Willy
! Rom header and SH2 init/exception code - must be first in object list
.text
! Standard MD Header at 0x000
.incbin "build/32x/m68k_crt0.bin", 0, 0x3C0
! Standard Mars Header at 0x3C0
.ascii "ClassiCube 32X " /* module name (16 chars) */
.long 0x00000000 /* version */
.long __text_end-0x02000000 /* Source (in ROM) */
.long 0x00000000 /* Destination (in SDRAM) */
.long __data_size /* Size */
.long 0x06000240 /* Master SH2 Jump */
.long 0x06000244 /* Slave SH2 Jump */
.long 0x06000000 /* Master SH2 VBR */
.long 0x06000120 /* Slave SH2 VBR */
! Standard MD startup code at 0x3F0
.incbin "build/32x/m68k_crt1.bin"
.data
! Master Vector Base Table at 0x06000000
.long mstart /* Cold Start PC */
.long 0x0603FC00 /* Cold Start SP */
.long mstart /* Manual Reset PC */
.long 0x0603FC00 /* Manual Reset SP */
.long main_err /* Illegal instruction */
.long 0x00000000 /* reserved */
.long main_err /* Invalid slot instruction */
.long 0x20100400 /* reserved */
.long 0x20100420 /* reserved */
.long main_err /* CPU address error */
.long main_err /* DMA address error */
.long main_err /* NMI vector */
.long main_err /* User break vector */
.space 76 /* reserved */
.long main_err /* TRAPA #32 */
.long main_err /* TRAPA #33 */
.long main_err /* TRAPA #34 */
.long main_err /* TRAPA #35 */
.long main_err /* TRAPA #36 */
.long main_err /* TRAPA #37 */
.long main_err /* TRAPA #38 */
.long main_err /* TRAPA #39 */
.long main_err /* TRAPA #40 */
.long main_err /* TRAPA #41 */
.long main_err /* TRAPA #42 */
.long main_err /* TRAPA #43 */
.long main_err /* TRAPA #44 */
.long main_err /* TRAPA #45 */
.long main_err /* TRAPA #46 */
.long main_err /* TRAPA #47 */
.long main_err /* TRAPA #48 */
.long main_err /* TRAPA #49 */
.long main_err /* TRAPA #50 */
.long main_err /* TRAPA #51 */
.long main_err /* TRAPA #52 */
.long main_err /* TRAPA #53 */
.long main_err /* TRAPA #54 */
.long main_err /* TRAPA #55 */
.long main_err /* TRAPA #56 */
.long main_err /* TRAPA #57 */
.long main_err /* TRAPA #58 */
.long main_err /* TRAPA #59 */
.long main_err /* TRAPA #60 */
.long main_err /* TRAPA #61 */
.long main_err /* TRAPA #62 */
.long main_err /* TRAPA #63 */
.long main_irq /* Level 1 IRQ */
.long main_irq /* Level 2 & 3 IRQ's */
.long main_irq /* Level 4 & 5 IRQ's */
.long main_irq /* PWM interupt */
.long main_irq /* Command interupt */
.long main_irq /* H Blank interupt */
.long main_irq /* V Blank interupt */
.long main_irq /* Reset Button */
! Slave Vector Base Table at 0x06000120
.long sstart /* Cold Start PC */
.long 0x06040000 /* Cold Start SP */
.long sstart /* Manual Reset PC */
.long 0x06040000 /* Manual Reset SP */
.long slav_err /* Illegal instruction */
.long 0x00000000 /* reserved */
.long slav_err /* Invalid slot instruction */
.long 0x20100400 /* reserved */
.long 0x20100420 /* reserved */
.long slav_err /* CPU address error */
.long slav_err /* DMA address error */
.long slav_err /* NMI vector */
.long slav_err /* User break vector */
.space 76 /* reserved */
.long slav_err /* TRAPA #32 */
.long slav_err /* TRAPA #33 */
.long slav_err /* TRAPA #34 */
.long slav_err /* TRAPA #35 */
.long slav_err /* TRAPA #36 */
.long slav_err /* TRAPA #37 */
.long slav_err /* TRAPA #38 */
.long slav_err /* TRAPA #39 */
.long slav_err /* TRAPA #40 */
.long slav_err /* TRAPA #41 */
.long slav_err /* TRAPA #42 */
.long slav_err /* TRAPA #43 */
.long slav_err /* TRAPA #44 */
.long slav_err /* TRAPA #45 */
.long slav_err /* TRAPA #46 */
.long slav_err /* TRAPA #47 */
.long slav_err /* TRAPA #48 */
.long slav_err /* TRAPA #49 */
.long slav_err /* TRAPA #50 */
.long slav_err /* TRAPA #51 */
.long slav_err /* TRAPA #52 */
.long slav_err /* TRAPA #53 */
.long slav_err /* TRAPA #54 */
.long slav_err /* TRAPA #55 */
.long slav_err /* TRAPA #56 */
.long slav_err /* TRAPA #57 */
.long slav_err /* TRAPA #58 */
.long slav_err /* TRAPA #59 */
.long slav_err /* TRAPA #60 */
.long slav_err /* TRAPA #61 */
.long slav_err /* TRAPA #62 */
.long slav_err /* TRAPA #63 */
.long slav_irq /* Level 1 IRQ */
.long slav_irq /* Level 2 & 3 IRQ's */
.long slav_irq /* Level 4 & 5 IRQ's */
.long slav_irq /* PWM interupt */
.long slav_irq /* Command interupt */
.long slav_irq /* H Blank interupt */
.long slav_irq /* V Blank interupt */
.long slav_irq /* Reset Button */
! The main SH2 starts here at 0x06000240
mstart:
bra mcont
nop
! The slave SH2 starts here at 0x06000244
sstart:
bra scont
nop
! Each section of code below has its own data table so that the code
! can be extended without worrying about the offsets becoming too big.
! This results in duplicate entries, but not so many that we care. :)
mcont:
! clear interrupt flags
mov.l _master_int_clr,r1
mov.w r0,@-r1 /* PWM INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* CMD INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* H INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* V INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* VRES INT clear */
mov.w r0,@r1
mov.l _master_stk,r15
! purge cache and turn it off
mov.l _master_cctl,r0
mov #0x10,r1
mov.b r1,@r0
! clear bss
mov #0,r0
mov.l _master_bss_start,r1
mov.l _master_bss_end,r2
0:
mov.l r0,@r1
cmp/eq r1,r2
bf/s 0b
add #4,r1
! wait for 68000 to finish init
mov.l _master_sts,r0
mov.l _master_ok,r1
1:
mov.l @r0,r2
nop
nop
cmp/eq r1,r2
bt 1b
! do all initializers
mov.l _master_do_init,r0
jsr @r0
nop
! let Slave SH2 run
mov #0,r1
mov.l r1,@(4,r0) /* clear slave status */
mov #0x80,r0
mov.l _master_adapter,r1
mov.b r0,@r1 /* set FM */
mov #0x00,r0
mov.b r0,@(1,r1) /* set int enables */
mov #0x20,r0
ldc r0,sr /* allow ints */
! purge cache, turn it on, and run main()
mov.l _master_cctl,r0
mov #0x11,r1
mov.b r1,@r0
mov.l _master_go,r0
jsr @r0
nop
! do all finishers
mov.l _master_do_fini,r0
jsr @r0
nop
2:
bra 2b
nop
.align 2
_master_int_clr:
.long 0x2000401E /* one word passed last int clr reg */
_master_stk:
.long 0x0603FC00 /* Cold Start SP */
_master_sts:
.long 0x20004020
_master_ok:
.ascii "M_OK"
_master_adapter:
.long 0x20004000
_master_cctl:
.long 0xFFFFFE92
_master_go:
.long _main
_master_bss_start:
.long __bss_start
_master_bss_end:
.long __bss_end
_master_do_init:
.long __INIT_SECTION__
_master_do_fini:
.long __FINI_SECTION__
scont:
! clear interrupt flags
mov.l _slave_int_clr,r1
mov.w r0,@-r1 /* PWM INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* CMD INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* H INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* V INT clear */
mov.w r0,@r1
mov.w r0,@-r1 /* VRES INT clear */
mov.w r0,@r1
mov.l _slave_stk,r15
! wait for Master SH2 and 68000 to finish init
mov.l _slave_sts,r0
mov.l _slave_ok,r1
1:
mov.l @r0,r2
nop
nop
cmp/eq r1,r2
bt 1b
mov.l _slave_adapter,r1
mov #0x00,r0
mov.b r0,@(1,r1) /* set int enables (different from master despite same address!) */
mov #0x20,r0
ldc r0,sr /* allow ints */
! purge cache, turn it on, and run slave()
mov.l _slave_cctl,r0
mov #0x11,r1
mov.b r1,@r0
mov.l _slave_go,r0
jmp @r0
nop
.align 2
_slave_int_clr:
.long 0x2000401E /* one word passed last int clr reg */
_slave_stk:
.long 0x06040000 /* Cold Start SP */
_slave_sts:
.long 0x20004024
_slave_ok:
.ascii "S_OK"
_slave_adapter:
.long 0x20004000
_slave_cctl:
.long 0xFFFFFE92
_slave_go:
.long _slave
! Master exception handler
main_err:
rte
nop
! Master IRQ handler
main_irq:
mov.l r0,@-r15
stc sr,r0 /* SR holds IRQ level in I3-I0 */
shlr2 r0
and #0x38,r0
cmp/eq #0x28,r0
bt main_h_irq
cmp/eq #0x18,r0
bt main_pwm_irq
cmp/eq #0x30,r0
bt main_v_irq
cmp/eq #0x20,r0
bt main_cmd_irq
cmp/eq #0x38,r0
bt main_vres_irq
mov.l @r15+,r0
rte
nop
main_v_irq:
mov.l r1,@-r15
mov.l mvi_mars_adapter,r1
mov.w r0,@(0x16,r1) /* clear V IRQ */
nop
nop
nop
nop
! handle V IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
mvi_mars_adapter:
.long 0x20004000
main_h_irq:
mov.l r1,@-r15
mov.l mhi_mars_adapter,r1
mov.w r0,@(0x18,r1) /* clear H IRQ */
nop
nop
nop
nop
! handle H IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
mhi_mars_adapter:
.long 0x20004000
main_cmd_irq:
mov.l r1,@-r15
mov.l mci_mars_adapter,r1
mov.w r0,@(0x1A,r1) /* clear CMD IRQ */
nop
nop
nop
nop
! handle CMD IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
mci_mars_adapter:
.long 0x20004000
main_pwm_irq:
mov.l r1,@-r15
mov.l mpi_mars_adapter,r1
mov.w r0,@(0x1C,r1) /* clear PWM IRQ */
nop
nop
nop
nop
! handle PWM IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
mpi_mars_adapter:
.long 0x20004000
main_vres_irq:
mov.l mvri_mars_adapter,r1
mov.w r0,@(0x14,r1) /* clear VRES IRQ */
nop
nop
nop
nop
mov #0x0F,r0
shll2 r0
shll2 r0
ldc r0,sr /* disallow ints */
mov.l mvri_master_stk,r15
mov.l mvri_master_vres,r0
jmp @r0
nop
.align 2
mvri_mars_adapter:
.long 0x20004000
mvri_master_stk:
.long 0x0603FC00 /* Cold Start SP */
mvri_master_vres:
.long main_reset
! Slave exception handler
slav_err:
rte
nop
! Slave IRQ handler
slav_irq:
mov.l r0,@-r15
stc sr,r0 /* SR holds IRQ level I3-I0 */
shlr2 r0
and #0x38,r0
cmp/eq #0x28,r0
bt slav_h_irq
cmp/eq #0x18,r0
bt slav_pwm_irq
cmp/eq #0x30,r0
bt slav_v_irq
cmp/eq #0x20,r0
bt slav_cmd_irq
cmp/eq #0x38,r0
bt slav_vres_irq
mov.l @r15+,r0
rte
nop
slav_v_irq:
mov.l r1,@-r15
mov.l svi_mars_adapter,r1
mov.w r0,@(0x16,r1) /* clear V IRQ */
nop
nop
nop
nop
! handle V IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
svi_mars_adapter:
.long 0x20004000
slav_h_irq:
mov.l r1,@-r15
mov.l shi_mars_adapter,r1
mov.w r0,@(0x18,r1) /* clear H IRQ */
nop
nop
nop
nop
! handle H IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
shi_mars_adapter:
.long 0x20004000
slav_cmd_irq:
mov.l r1,@-r15
mov.l sci_mars_adapter,r1
mov.w r0,@(0x1A,r1) /* clear CMD IRQ */
nop
nop
nop
nop
! handle CMD IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
sci_mars_adapter:
.long 0x20004000
slav_pwm_irq:
mov.l r1,@-r15
mov.l spi_mars_adapter,r1
mov.w r0,@(0x1C,r1) /* clear PWM IRQ */
nop
nop
nop
nop
! handle PWM IRQ
mov.l @r15+,r1
mov.l @r15+,r0
rte
nop
.align 2
spi_mars_adapter:
.long 0x20004000
slav_vres_irq:
mov.l svri_mars_adapter,r1
mov.w r0,@(0x14,r1) /* clear VRES IRQ */
nop
nop
nop
nop
mov #0x0F,r0
shll2 r0
shll2 r0
ldc r0,sr /* disallow ints */
mov.l svri_slave_stk,r15
mov.l svri_slave_vres,r0
jmp @r0
nop
.align 2
svri_mars_adapter:
.long 0x20004000
svri_slave_stk:
.long 0x06040000 /* Cold Start SP */
svri_slave_vres:
.long slav_reset
! Fast memcpy function - copies longs, runs from sdram for speed
! On entry: r4 = dst, r5 = src, r6 = len (in longs)
.align 4
.global _fast_memcpy
_fast_memcpy:
mov.l @r5+,r3
mov.l r3,@r4
dt r6
bf/s _fast_memcpy
add #4,r4
rts
nop
! Cache clear line function
! On entry: r4 = ptr - should be 16 byte aligned
.align 4
.global _CacheClearLine
_CacheClearLine:
mov.l _cache_flush,r0
or r0,r4
mov #0,r0
mov.l r0,@r4
rts
nop
.align 2
_cache_flush:
.long 0x40000000
! Cache control function
! On entry: r4 = cache mode => 0x10 = CP, 0x08 = TW, 0x01 = CE
.align 4
.global _CacheControl
_CacheControl:
mov.l _sh2_cctl,r0
mov.b r4,@r0
rts
nop
.align 2
_sh2_cctl:
.long 0xFFFFFE92
! void ScreenStretch(int src, int width, int height, int interp);
! On entry: r4 = src pointer, r5 = width, r6 = height, r7 = interpolate
.align 4
.global _ScreenStretch
_ScreenStretch:
cmp/pl r7
bt ss_interp
! stretch screen without interpolation
0:
mov r5,r3
shll r3
mov r3,r2
shll r2
add r4,r3
add r4,r2
1:
add #-2,r3
mov.w @r3,r0
extu.w r0,r1
shll16 r0
or r1,r0
mov.l r0,@-r2
cmp/eq r3,r4
bf 1b
/* next line */
mov.w ss_pitch,r0
dt r6
bf/s 0b
add r0,r4
rts
nop
ss_interp:
! stretch screen with interpolation
0:
mov r5,r3
shll r3
mov r3,r2
shll r2
add r4,r3
add r4,r2
mov #0,r7
1:
add #-2,r3
mov.w @r3,r0
mov.w ss_mask,r1
and r0,r1 /* masked curr pixel */
shll16 r0
add r1,r7 /* add to masked prev pixel */
shlr r7 /* blended pixel */
or r7,r0 /* curr pixel << 16 | blended pixel */
mov r1,r7 /* masked prev pixel = masked curr pixel */
mov.l r0,@-r2
cmp/eq r3,r4
bf 1b
/* next line */
mov.w ss_pitch,r0
dt r6
bf/s 0b
add r0,r4
rts
nop
ss_mask:
.word 0x7BDE
ss_pitch:
.word 640
.align 2
.text
main_reset:
! do any master SH2 specific reset code here
mov.l slav_st,r0
mov.l slav_ok,r1
0:
mov.l @r0,r2
nop
nop
cmp/eq r1,r2
bf 0b /* wait for slave */
! recopy rom data to sdram
mov.l rom_header,r1
mov.l @r1,r2 /* src relative to start of rom */
mov.l @(4,r1),r3 /* dst relative to start of sdram */
mov.l @(8,r1),r4 /* size (longword aligned) */
mov.l rom_start,r1
add r1,r2
mov.l sdram_start,r1
add r1,r3
shlr2 r4 /* number of longs */
add #-1,r4
1:
mov.l @r2+,r0
mov.l r0,@r3
add #4,r3
dt r4
bf 1b
mov.l main_st,r0
mov.l main_ok,r1
mov.l r1,@r0 /* tell everyone reset complete */
mov.l main_go,r0
jmp @r0
nop
slav_reset:
! do any slave SH2 specific reset code here
mov.l slav_st,r0
mov.l slav_ok,r1
mov.l r1,@r0 /* tell master to start reset */
mov.l main_st,r0
mov.l main_ok,r1
0:
mov.l @r0,r2
nop
nop
cmp/eq r1,r2
bf 0b /* wait for master to do the work */
mov.l slav_go,r0
jmp @r0
nop
.align 2
main_st:
.long 0x20004020
main_ok:
.ascii "M_OK"
main_go:
.long mstart
rom_header:
.long 0x220003D4
rom_start:
.long 0x22000000
sdram_start:
.long 0x26000000
slav_st:
.long 0x20004024
slav_ok:
.ascii "S_OK"
slav_go:
.long sstart
.global _start
_start:

127
misc/3ds/Makefile Normal file
View File

@@ -0,0 +1,127 @@
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro)
endif
#---------------------------------------------------------------------------------
# Configurable options
#---------------------------------------------------------------------------------
# Name of the final output
TARGET = ClassiCube-3ds
# List of directories containing source code
SOURCE_DIRS = src src/3ds third_party/bearssl/src
# List of directories containing shader files
SHDR_DIRS = misc/3ds
# List of directories containing more header files
INCLUDES = -Ithird_party/bearssl/inc
# Directory where object files are placed
BUILD_DIR = build/3ds
APP_ICON = misc/3ds/icon.png
APP_TITLE = ClassiCube
APP_DESCRIPTION = Simple block building sandbox
APP_AUTHOR = ClassiCube team
CIA_BANNER_BIN = misc/3ds/banner.bin
CIA_ICON_BIN = misc/3ds/icon.bin
CIA_SPEC_RSF = misc/3ds/spec.rsf
#---------------------------------------------------------------------------------
# Code generation
#---------------------------------------------------------------------------------
S_FILES = $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.S))
C_FILES = $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.S=%.o)))
PICAFILES := $(foreach dir,$(SHDR_DIRS),$(notdir $(wildcard $(dir)/*.v.pica)))
OBJS += $(addprefix $(BUILD_DIR)/, $(PICAFILES:.v.pica=.shbin.o))
ARCH = -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
CFLAGS = -g -Wall -O2 -mword-relocations -ffunction-sections $(ARCH) $(INCLUDE) -D__3DS__
ASFLAGS = -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH)
LIBS = -lctru -lm
CTRULIB = $(DEVKITPRO)/libctru
INCLUDES += $(foreach dir, $(CTRULIB), -I$(dir)/include)
LDFLAGS += $(foreach dir, $(CTRULIB), -L$(dir)/lib)
# Dependency tracking
DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.d
DEPFILES := $(OBJS:%.o=%.d)
#---------------------------------------------------------------------------------
# Compiler tools
#---------------------------------------------------------------------------------
PREFIX := $(DEVKITPRO)/devkitARM/bin/arm-none-eabi-
ARM_AS := $(PREFIX)as
ARM_CC := $(PREFIX)gcc
ARM_CXX := $(PREFIX)g++
_DSXTOOL := $(DEVKITPRO)/tools/bin/3dsxtool
SMDHTOOL := $(DEVKITPRO)/tools/bin/smdhtool
PICASSO := $(DEVKITPRO)/tools/bin/picasso
BIN2S := $(DEVKITPRO)/tools/bin/bin2s
#---------------------------------------------------------------------------------
# Main targets
#---------------------------------------------------------------------------------
default: $(BUILD_DIR) $(TARGET).cia
clean:
rm $(TARGET).cia $(TARGET).3dsx $(TARGET).elf $(OBJS)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
#---------------------------------------------------------------------------------
# Executable generation
#---------------------------------------------------------------------------------
$(TARGET).elf: $(OBJS)
$(ARM_CC) $(LDFLAGS) $^ -o $@ $(LIBS)
$(BUILD_DIR).smdh: $(APP_ICON)
$(SMDHTOOL) --create "$(APP_TITLE)" "$(APP_DESCRIPTION)" "$(APP_AUTHOR)" $(APP_ICON) $@
$(TARGET).3dsx: $(TARGET).elf $(BUILD_DIR).smdh
$(_DSXTOOL) $< $@ --smdh=$(BUILD_DIR).smdh
$(BUILD_DIR)/makerom:
wget https://github.com/3DSGuy/Project_CTR/releases/download/makerom-v0.18.3/makerom-v0.18.3-ubuntu_x86_64.zip -O $(BUILD_DIR)/makerom.zip
unzip $(BUILD_DIR)/makerom.zip -d $(BUILD_DIR)
chmod +x $(BUILD_DIR)/makerom
$(TARGET).cia : $(TARGET).3dsx $(BUILD_DIR)/makerom
$(BUILD_DIR)/makerom -f cia -o $(TARGET).cia -elf $(TARGET).elf -rsf $(CIA_SPEC_RSF) -icon $(CIA_ICON_BIN) -banner $(CIA_BANNER_BIN) -exefslogo -target t
#---------------------------------------------------------------------------------
# Object generation
#---------------------------------------------------------------------------------
$(BUILD_DIR)/%.o: src/%.c
$(ARM_CC) $(CFLAGS) $(INCLUDES) $(DEPFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o: src/3ds/%.c
$(ARM_CC) $(CFLAGS) $(INCLUDES) $(DEPFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o: third_party/bearssl/src/%.c
$(ARM_CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
$(BUILD_DIR)/%.shbin: misc/3ds/%.v.pica
$(PICASSO) $< -o $@
$(BUILD_DIR)/%.shbin.o: $(BUILD_DIR)/%.shbin
$(BIN2S) $< | $(ARM_AS) -o $@
#---------------------------------------------------------------------------------
# Dependency tracking
#---------------------------------------------------------------------------------
$(DEPFILES):
include $(wildcard $(DEPFILES))

BIN
misc/3ds/audio.wav Normal file

Binary file not shown.

BIN
misc/3ds/banner.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

33
misc/3ds/coloured.v.pica Normal file
View File

@@ -0,0 +1,33 @@
; Vertex shader for rendering coloured vertices for PICA200 GPU on the Nintendo 3DS
; ==================================================================================
; Uniforms
.fvec MVP[4];
; Constants
.constf ONE_DIV_255(0.003921568627, 0.003921568627, 0.003921568627, 0.003921568627)
; Outputs
.out out_pos position
.out out_col color
; Inputs (defined as aliases for convenience)
.alias in_pos v0
.alias in_col v1
.proc main
; r0 = in_pos
mov r0, in_pos
; out_pos = MVP * r0
dp4 out_pos.x, MVP[0], r0
dp4 out_pos.y, MVP[1], r0
dp4 out_pos.z, MVP[2], r0
dp4 out_pos.w, MVP[3], r0
; out_col = in_col * ONE_DIV_255
mul out_col, ONE_DIV_255, in_col
end
.end

BIN
misc/3ds/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

38
misc/3ds/offset.v.pica Normal file
View File

@@ -0,0 +1,38 @@
; Vertex shader for rendering textured vertices with an offset for PICA200 GPU on the Nintendo 3DS
; ==================================================================================
; Uniforms
.fvec MVP[4];
.fvec tex_offset;
; Constants
.constf ONE_DIV_255(0.003921568627, 0.003921568627, 0.003921568627, 0.003921568627)
; Outputs
.out out_pos position
.out out_col color
.out out_tex texcoord0
; Inputs (defined as aliases for convenience)
.alias in_pos v0
.alias in_col v1
.alias in_tex v2
.proc main
; r0 = in_pos
mov r0, in_pos
; out_pos = MVP * r0
dp4 out_pos.x, MVP[0], r0
dp4 out_pos.y, MVP[1], r0
dp4 out_pos.z, MVP[2], r0
dp4 out_pos.w, MVP[3], r0
; out_col = in_col * ONE_DIV_255
mul out_col, ONE_DIV_255, in_col
; out_tex = in_tex + tex_offset
add out_tex, tex_offset, in_tex
end
.end

5
misc/3ds/readme.md Normal file
View File

@@ -0,0 +1,5 @@
Commands used to generate the .bin files:
`bannertool makebanner -i banner.png -a audio.wav -o banner.bin`
`bannertool makesmdh -s ClassiCube -l ClassiCube -p UnknownShadow200 -i icon.png -o icon.bin`

204
misc/3ds/spec.rsf Normal file
View File

@@ -0,0 +1,204 @@
# https://github.com/msikma/3ds-tpl
# https://gist.github.com/jakcron/9f9f02ffd94d98a72632
BasicInfo:
Title : ClassiCube
CompanyCode : "00"
ProductCode : CCBE
ContentType : Application
Logo : Nintendo
TitleInfo:
UniqueId : 0x00CCBE
Category : Application
CardInfo:
MediaSize : 128MB # 128MB / 256MB / 512MB / 1GB / 2GB / 4GB
MediaType : Card1 # Card1 / Card2
CardDevice : NorFlash # NorFlash(Pick this if you use savedata) / None
Option:
UseOnSD : true # true if App is to be installed to SD
FreeProductCode : true # Removes limitations on ProductCode
MediaFootPadding : false # If true CCI files are created with padding
EnableCrypt : false # Enables encryption for NCCH and CIA
EnableCompress : true # Compresses exefs code
AccessControlInfo:
#UseExtSaveData : true
#ExtSaveDataId: 0xff3ff
#UseExtendedSaveDataAccessControl: true
#AccessibleSaveDataIds: [0x101, 0x202, 0x303, 0x404, 0x505, 0x606]
SystemControlInfo:
SaveDataSize: 128KB
RemasterVersion: 0
StackSize: 0x40000
AccessControlInfo:
FileSystemAccess:
- Debug
- DirectSdmc
- DirectSdmcWrite
IdealProcessor : 0
AffinityMask : 1
Priority : 16
SystemMode : 80MB
MaxCpu : 0x9E # Default
DisableDebug : false
EnableForceDebug : false
CanWriteSharedPage : false
CanUsePrivilegedPriority : false
CanUseNonAlphabetAndNumber : false
PermitMainFunctionArgument : false
CanShareDeviceMemory : false
RunnableOnSleep : false
SpecialMemoryArrange : false
CoreVersion : 2
DescVersion : 2
ReleaseKernelMajor : "02"
ReleaseKernelMinor : "33"
MemoryType : Application
HandleTableSize: 512
# New3DS Exclusive Process Settings
SystemModeExt : 124MB # Legacy(Default)/124MB/178MB Legacy:Use Old3DS SystemMode
CpuSpeed : 804MHz # 268MHz(Default)/804MHz
EnableL2Cache : true # false(default)/true
CanAccessCore2 : true
# Virtual Address Mappings
IORegisterMapping:
- 1ff50000-1ff57fff # DSP memory
- 1ff70000-1ff77fff
MemoryMapping:
- 1f000000-1f5fffff:r # VRAM
SystemCallAccess:
ArbitrateAddress: 34
Break: 60
CancelTimer: 28
ClearEvent: 25
ClearTimer: 29
CloseHandle: 35
ConnectToPort: 45
ControlMemory: 1
CreateAddressArbiter: 33
CreateEvent: 23
CreateMemoryBlock: 30
CreateMutex: 19
CreateSemaphore: 21
CreateThread: 8
CreateTimer: 26
DuplicateHandle: 39
ExitProcess: 3
ExitThread: 9
GetCurrentProcessorNumber: 17
GetHandleInfo: 41
GetProcessId: 53
GetProcessIdOfThread: 54
GetProcessIdealProcessor: 6
GetProcessInfo: 43
GetResourceLimit: 56
GetResourceLimitCurrentValues: 58
GetResourceLimitLimitValues: 57
GetSystemInfo: 42
GetSystemTick: 40
GetThreadContext: 59
GetThreadId: 55
GetThreadIdealProcessor: 15
GetThreadInfo: 44
GetThreadPriority: 11
MapMemoryBlock: 31
OutputDebugString: 61
QueryMemory: 2
ReleaseMutex: 20
ReleaseSemaphore: 22
SendSyncRequest1: 46
SendSyncRequest2: 47
SendSyncRequest3: 48
SendSyncRequest4: 49
SendSyncRequest: 50
SetThreadPriority: 12
SetTimer: 27
SignalEvent: 24
SleepThread: 10
UnmapMemoryBlock: 32
WaitSynchronization1: 36
WaitSynchronizationN: 37
InterruptNumbers:
# Service List
# Maximum 34 services (32 if firmware is prior to 9.3.0)
ServiceAccessControl:
- APT:U
- $hioFIO
- $hostio0
- $hostio1
- ac:u
- boss:U
- cam:u
- cecd:u
- cfg:u
- dlp:FKCL
- dlp:SRVR
- dsp::DSP
- frd:u
- fs:USER
- gsp::Gpu
- hid:USER
- mic:u
- ndm:u
- news:s
- nwm::UDS
- ptm:u
- pxi:dev
- soc:U
- gsp::Lcd
- y2r:u
- ldr:ro
- ir:USER
- ir:u
- csnd:SND
- am:u
- ns:s
SystemControlInfo:
# Modules that run services listed above should be included below
# Maximum 48 dependencies
# If a module is listed that isn't present on the 3DS, the title will get stuck at the logo (3ds waves)
# So act, nfc and qtm are commented for 4.x support. Uncomment if you need these.
# <module name>:<module titleid>
Dependency:
ac: 0x0004013000002402L
am: 0x0004013000001502L
boss: 0x0004013000003402L
camera: 0x0004013000001602L
cecd: 0x0004013000002602L
cfg: 0x0004013000001702L
codec: 0x0004013000001802L
csnd: 0x0004013000002702L
dlp: 0x0004013000002802L
dsp: 0x0004013000001a02L
friends: 0x0004013000003202L
gpio: 0x0004013000001b02L
gsp: 0x0004013000001c02L
hid: 0x0004013000001d02L
i2c: 0x0004013000001e02L
ir: 0x0004013000003302L
mcu: 0x0004013000001f02L
mic: 0x0004013000002002L
ndm: 0x0004013000002b02L
news: 0x0004013000003502L
nim: 0x0004013000002c02L
nwm: 0x0004013000002d02L
pdn: 0x0004013000002102L
ps: 0x0004013000003102L
ptm: 0x0004013000002202L
ro: 0x0004013000003702L
socket: 0x0004013000002e02L
spi: 0x0004013000002302L

37
misc/3ds/textured.v.pica Normal file
View File

@@ -0,0 +1,37 @@
; Vertex shader for rendering textured vertices for PICA200 GPU on the Nintendo 3DS
; ==================================================================================
; Uniforms
.fvec MVP[4];
; Constants
.constf ONE_DIV_255(0.003921568627, 0.003921568627, 0.003921568627, 0.003921568627)
; Outputs
.out out_pos position
.out out_col color
.out out_tex texcoord0
; Inputs (defined as aliases for convenience)
.alias in_pos v0
.alias in_col v1
.alias in_tex v2
.proc main
; r0 = in_pos
mov r0, in_pos
; out_pos = MVP * r0
dp4 out_pos.x, MVP[0], r0
dp4 out_pos.y, MVP[1], r0
dp4 out_pos.z, MVP[2], r0
dp4 out_pos.w, MVP[3], r0
; out_col = in_col * ONE_DIV_255
mul out_col, ONE_DIV_255, in_col
; out_tex = in_tex
mov out_tex, in_tex
end
.end

BIN
misc/CCicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
misc/CCicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
IgnorableNamespaces="uap mp">
<Identity
Name="64f1d536-965b-4190-90d3-47d861786f88"
Publisher="CN=ClassiCube"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="64f1d536-965b-4190-90d3-47d861786f88" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>ClassiCube-UWP</DisplayName>
<PublisherDisplayName>ClassiCube</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="ClassiCube_UWP.App">
<uap:VisualElements
DisplayName="ClassiCube-UWP"
Description="ClassiCube-UWP"
BackgroundColor="transparent" Square44x44Logo="Assets\Square44x44Logo.png" Square150x150Logo="Assets\Square150x150Logo.png">
<uap:DefaultTile>
<uap:ShowNameOnTiles>
<uap:ShowOn Tile="square150x150Logo"/>
</uap:ShowNameOnTiles>
</uap:DefaultTile>
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
</Capabilities>
</Package>

809
misc/UWP/Platform_UWP.cpp Normal file
View File

@@ -0,0 +1,809 @@
#include "../../src/Core.h"
#include "../../src/_PlatformBase.h"
#include "../../src/Stream.h"
#include "../../src/SystemFonts.h"
#include "../../src/Funcs.h"
#include "../../src/Utils.h"
#include "../../src/Errors.h"
#define WIN32_LEAN_AND_MEAN
#define NOSERVICE
#define NOMCX
#define NOIME
#ifndef UNICODE
#define UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <shellapi.h>
#include <wincrypt.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.System.h>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::System;
static HANDLE heap;
const cc_result ReturnCode_FileShareViolation = ERROR_SHARING_VIOLATION;
const cc_result ReturnCode_FileNotFound = ERROR_FILE_NOT_FOUND;
const cc_result ReturnCode_DirectoryExists = ERROR_ALREADY_EXISTS;
const cc_result ReturnCode_SocketInProgess = WSAEINPROGRESS;
const cc_result ReturnCode_SocketWouldBlock = WSAEWOULDBLOCK;
const cc_result ReturnCode_SocketDropped = WSAECONNRESET;
const char* Platform_AppNameSuffix = "";
cc_bool Platform_ReadonlyFilesystem;
cc_uint8 Platform_Flags = PLAT_FLAG_SINGLE_PROCESS;
#define UWP_STRING(str) ((wchar_t*)(str)->uni)
/*########################################################################################################################*
*---------------------------------------------------------Memory----------------------------------------------------------*
*#########################################################################################################################*/
void* Mem_Set(void* dst, cc_uint8 value, unsigned numBytes) { return memset( dst, value, numBytes); }
void* Mem_Copy(void* dst, const void* src, unsigned numBytes) { return memcpy( dst, src, numBytes); }
void* Mem_Move(void* dst, const void* src, unsigned numBytes) { return memmove(dst, src, numBytes); }
void* Mem_TryAlloc(cc_uint32 numElems, cc_uint32 elemsSize) {
cc_uint32 size = CalcMemSize(numElems, elemsSize);
return size ? HeapAlloc(heap, 0, size) : NULL;
}
void* Mem_TryAllocCleared(cc_uint32 numElems, cc_uint32 elemsSize) {
cc_uint32 size = CalcMemSize(numElems, elemsSize);
return size ? HeapAlloc(heap, HEAP_ZERO_MEMORY, size) : NULL;
}
void* Mem_TryRealloc(void* mem, cc_uint32 numElems, cc_uint32 elemsSize) {
cc_uint32 size = CalcMemSize(numElems, elemsSize);
return size ? HeapReAlloc(heap, 0, mem, size) : NULL;
}
void Mem_Free(void* mem) {
if (mem) HeapFree(heap, 0, mem);
}
/*########################################################################################################################*
*------------------------------------------------------Logging/Time-------------------------------------------------------*
*#########################################################################################################################*/
/* TODO: check this is actually accurate */
static cc_uint64 sw_freqMul = 1, sw_freqDiv = 1;
cc_uint64 Stopwatch_ElapsedMicroseconds(cc_uint64 beg, cc_uint64 end) {
if (end < beg) return 0;
return ((end - beg) * sw_freqMul) / sw_freqDiv;
}
static HANDLE conHandle;
static BOOL hasDebugger;
void Platform_Log(const char* msg, int len) {
char tmp[2048 + 1];
DWORD wrote;
if (conHandle) {
WriteFile(conHandle, msg, len, &wrote, NULL);
WriteFile(conHandle, "\n", 1, &wrote, NULL);
}
if (!hasDebugger) return;
len = min(len, 2048);
Mem_Copy(tmp, msg, len); tmp[len] = '\0';
OutputDebugStringA(tmp);
OutputDebugStringA("\n");
}
#define FILETIME_EPOCH 50491123200ULL
#define FILETIME_UNIX_EPOCH 11644473600ULL
#define FileTime_TotalSecs(time) ((time / 10000000) + FILETIME_EPOCH)
#define FileTime_UnixTime(time) ((time / 10000000) - FILETIME_UNIX_EPOCH)
TimeMS DateTime_CurrentUTC(void) {
FILETIME ft;
cc_uint64 raw;
GetSystemTimeAsFileTime(&ft);
/* in 100 nanosecond units, since Jan 1 1601 */
raw = ft.dwLowDateTime | ((cc_uint64)ft.dwHighDateTime << 32);
return FileTime_TotalSecs(raw);
}
void DateTime_CurrentLocal(struct cc_datetime* t) {
SYSTEMTIME localTime;
GetLocalTime(&localTime);
t->year = localTime.wYear;
t->month = localTime.wMonth;
t->day = localTime.wDay;
t->hour = localTime.wHour;
t->minute = localTime.wMinute;
t->second = localTime.wSecond;
}
static cc_bool sw_highRes;
cc_uint64 Stopwatch_Measure(void) {
LARGE_INTEGER t;
FILETIME ft;
if (sw_highRes) {
QueryPerformanceCounter(&t);
return (cc_uint64)t.QuadPart;
} else {
GetSystemTimeAsFileTime(&ft);
return (cc_uint64)ft.dwLowDateTime | ((cc_uint64)ft.dwHighDateTime << 32);
}
}
/*########################################################################################################################*
*-------------------------------------------------------Crash handling----------------------------------------------------*
*#########################################################################################################################*/
static const char* ExceptionDescribe(cc_uint32 code) {
switch (code) {
case EXCEPTION_ACCESS_VIOLATION: return "ACCESS_VIOLATION";
case EXCEPTION_ILLEGAL_INSTRUCTION: return "ILLEGAL_INSTRUCTION";
case EXCEPTION_INT_DIVIDE_BY_ZERO: return "DIVIDE_BY_ZERO";
}
return NULL;
}
static LONG WINAPI UnhandledFilter(struct _EXCEPTION_POINTERS* info) {
cc_string msg; char msgBuffer[128 + 1];
const char* desc;
cc_uint32 code;
cc_uintptr addr;
code = (cc_uint32)info->ExceptionRecord->ExceptionCode;
addr = (cc_uintptr)info->ExceptionRecord->ExceptionAddress;
desc = ExceptionDescribe(code);
String_InitArray_NT(msg, msgBuffer);
if (desc) {
String_Format2(&msg, "Unhandled %c error at %x", desc, &addr);
} else {
String_Format2(&msg, "Unhandled exception 0x%h at %x", &code, &addr);
}
DWORD numArgs = info->ExceptionRecord->NumberParameters;
if (numArgs) {
numArgs = min(numArgs, EXCEPTION_MAXIMUM_PARAMETERS);
String_AppendConst(&msg, " [");
for (DWORD i = 0; i < numArgs; i++)
{
String_Format1(&msg, "0x%x,", &info->ExceptionRecord->ExceptionInformation[i]);
}
String_Append(&msg, ']');
}
msg.buffer[msg.length] = '\0';
Logger_DoAbort(0, msg.buffer, info->ContextRecord);
return EXCEPTION_EXECUTE_HANDLER; /* TODO: different flag */
}
void CrashHandler_Install(void) {
SetUnhandledExceptionFilter(UnhandledFilter);
}
void Process_Abort2(cc_result result, const char* raw_msg) {
Logger_DoAbort(result, raw_msg, NULL);
}
/*########################################################################################################################*
*-----------------------------------------------------Directory/File------------------------------------------------------*
*#########################################################################################################################*/
void Directory_GetCachePath(cc_string* path) { }
void Platform_EncodePath(cc_filepath* dst, const cc_string* src) {
Platform_EncodeString(dst, src);
}
cc_result Directory_Create(const cc_filepath* path) {
if (CreateDirectoryW(UWP_STRING(path), NULL)) return 0;
return GetLastError();
}
int File_Exists(const cc_filepath* path) {
DWORD attribs = GetFileAttributesW(UWP_STRING(path));
return attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY);
}
static cc_result Directory_EnumCore(const cc_string* dirPath, const cc_string* file, DWORD attribs,
void* obj, Directory_EnumCallback callback) {
cc_string path; char pathBuffer[MAX_PATH + 10];
int is_dir;
/* ignore . and .. entry */
if (file->length == 1 && file->buffer[0] == '.') return 0;
if (file->length == 2 && file->buffer[0] == '.' && file->buffer[1] == '.') return 0;
String_InitArray(path, pathBuffer);
String_Format2(&path, "%s/%s", dirPath, file);
is_dir = attribs & FILE_ATTRIBUTE_DIRECTORY;
callback(&path, obj, is_dir);
return 0;
}
cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCallback callback) {
cc_string path; char pathBuffer[MAX_PATH + 10];
WIN32_FIND_DATAW eW;
int i, ansi = false;
cc_filepath str;
HANDLE find;
cc_result res;
/* Need to append \* to search for files in directory */
String_InitArray(path, pathBuffer);
String_Format1(&path, "%s\\*", dirPath);
Platform_EncodePath(&str, &path);
find = FindFirstFileW(UWP_STRING(&str), &eW);
if (!find || find == INVALID_HANDLE_VALUE)
return GetLastError();
do {
path.length = 0;
for (i = 0; i < MAX_PATH && eW.cFileName[i]; i++) {
/* TODO: UTF16 to codepoint conversion */
String_Append(&path, Convert_CodepointToCP437(eW.cFileName[i]));
}
if ((res = Directory_EnumCore(dirPath, &path, eW.dwFileAttributes, obj, callback))) return res;
} while (FindNextFileW(find, &eW));
res = GetLastError(); /* return code from FindNextFile */
FindClose(find);
return res == ERROR_NO_MORE_FILES ? 0 : res;
}
static cc_result DoFile(cc_file* file, const cc_filepath* path, DWORD access, DWORD createMode) {
*file = CreateFile2(UWP_STRING(path), access, FILE_SHARE_READ, createMode, NULL);
if (*file && *file != INVALID_HANDLE_VALUE) return 0;
return GetLastError();
}
cc_result File_Open(cc_file* file, const cc_filepath* path) {
return DoFile(file, path, GENERIC_READ, OPEN_EXISTING);
}
cc_result File_Create(cc_file* file, const cc_filepath* path) {
return DoFile(file, path, GENERIC_WRITE | GENERIC_READ, CREATE_ALWAYS);
}
cc_result File_OpenOrCreate(cc_file* file, const cc_filepath* path) {
return DoFile(file, path, GENERIC_WRITE | GENERIC_READ, OPEN_ALWAYS);
}
cc_result File_Read(cc_file file, void* data, cc_uint32 count, cc_uint32* bytesRead) {
/* NOTE: the (DWORD*) cast assumes that sizeof(long) is 4 */
BOOL success = ReadFile(file, data, count, (DWORD*)bytesRead, NULL);
return success ? 0 : GetLastError();
}
cc_result File_Write(cc_file file, const void* data, cc_uint32 count, cc_uint32* bytesWrote) {
/* NOTE: the (DWORD*) cast assumes that sizeof(long) is 4 */
BOOL success = WriteFile(file, data, count, (DWORD*)bytesWrote, NULL);
return success ? 0 : GetLastError();
}
cc_result File_Close(cc_file file) {
return CloseHandle(file) ? 0 : GetLastError();
}
cc_result File_Seek(cc_file file, int offset, int seekType) {
static cc_uint8 modes[] = { FILE_BEGIN, FILE_CURRENT, FILE_END };
DWORD pos = SetFilePointer(file, offset, NULL, modes[seekType]);
return pos != INVALID_SET_FILE_POINTER ? 0 : GetLastError();
}
cc_result File_Position(cc_file file, cc_uint32* pos) {
*pos = SetFilePointer(file, 0, NULL, FILE_CURRENT);
return *pos != INVALID_SET_FILE_POINTER ? 0 : GetLastError();
}
cc_result File_Length(cc_file file, cc_uint32* len) {
LARGE_INTEGER raw;
if (!GetFileSizeEx(file, &raw)) return GetLastError();
*len = raw.QuadPart;
return 0;
}
/*########################################################################################################################*
*--------------------------------------------------------Threading--------------------------------------------------------*
*#############################################################################################################p############*/
void Thread_Sleep(cc_uint32 milliseconds) { Sleep(milliseconds); }
static DWORD WINAPI ExecThread(void* param) {
Thread_StartFunc func = (Thread_StartFunc)param;
func();
return 0;
}
void Thread_Run(void** handle, Thread_StartFunc func, int stackSize, const char* name) {
DWORD threadID;
HANDLE thread = CreateThread(NULL, 0, ExecThread, (void*)func, CREATE_SUSPENDED, &threadID);
if (!thread) Process_Abort2(GetLastError(), "Creating thread");
*handle = thread;
ResumeThread(thread);
}
void Thread_Detach(void* handle) {
if (!CloseHandle((HANDLE)handle)) {
Process_Abort2(GetLastError(), "Freeing thread handle");
}
}
void Thread_Join(void* handle) {
WaitForSingleObject((HANDLE)handle, INFINITE);
Thread_Detach(handle);
}
void* Mutex_Create(const char* name) {
CRITICAL_SECTION* ptr = (CRITICAL_SECTION*)Mem_Alloc(1, sizeof(CRITICAL_SECTION), "mutex");
InitializeCriticalSection(ptr);
return ptr;
}
void Mutex_Free(void* handle) {
DeleteCriticalSection((CRITICAL_SECTION*)handle);
Mem_Free(handle);
}
void Mutex_Lock(void* handle) { EnterCriticalSection((CRITICAL_SECTION*)handle); }
void Mutex_Unlock(void* handle) { LeaveCriticalSection((CRITICAL_SECTION*)handle); }
void* Waitable_Create(const char* name) {
void* handle = CreateEventA(NULL, false, false, NULL);
if (!handle) {
Process_Abort2(GetLastError(), "Creating waitable");
}
return handle;
}
void Waitable_Free(void* handle) {
if (!CloseHandle((HANDLE)handle)) {
Process_Abort2(GetLastError(), "Freeing waitable");
}
}
void Waitable_Signal(void* handle) { SetEvent((HANDLE)handle); }
void Waitable_Wait(void* handle) {
WaitForSingleObject((HANDLE)handle, INFINITE);
}
void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) {
WaitForSingleObject((HANDLE)handle, milliseconds);
}
/*########################################################################################################################*
*---------------------------------------------------------Socket----------------------------------------------------------*
*#########################################################################################################################*/
/* Sanity check to ensure cc_sockaddr struct is large enough to contain all socket addresses supported by this platform */
static char sockaddr_size_check[sizeof(SOCKADDR_STORAGE) < CC_SOCKETADDR_MAXSIZE ? 1 : -1];
static cc_result ParseHostNew(char* host, int port, cc_sockaddr* addrs, int* numValidAddrs) {
char portRaw[32]; cc_string portStr;
struct addrinfo hints = { 0 };
struct addrinfo* result;
struct addrinfo* cur;
int i = 0;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
String_InitArray(portStr, portRaw);
String_AppendInt(&portStr, port);
portRaw[portStr.length] = '\0';
int res = getaddrinfo(host, portRaw, &hints, &result);
if (res == WSAHOST_NOT_FOUND) return SOCK_ERR_UNKNOWN_HOST;
if (res) return res;
/* Prefer IPv4 addresses first */
for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next)
{
if (cur->ai_family != AF_INET) continue;
SocketAddr_Set(&addrs[i], cur->ai_addr, cur->ai_addrlen); i++;
}
for (cur = result; cur && i < SOCKET_MAX_ADDRS; cur = cur->ai_next)
{
if (cur->ai_family == AF_INET) continue;
SocketAddr_Set(&addrs[i], cur->ai_addr, cur->ai_addrlen); i++;
}
freeaddrinfo(result);
*numValidAddrs = i;
return i == 0 ? ERR_INVALID_ARGUMENT : 0;
}
cc_result Socket_ParseAddress(const cc_string* address, int port, cc_sockaddr* addrs, int* numValidAddrs) {
SOCKADDR_IN* addr4 = (SOCKADDR_IN* )addrs[0].data;
SOCKADDR_IN6* addr6 = (SOCKADDR_IN6*)addrs[0].data;
cc_winstring str;
INT size;
*numValidAddrs = 0;
Platform_EncodeString(&str, address);
size = sizeof(*addr4);
if (!WSAStringToAddressW(UWP_STRING(&str), AF_INET, NULL, (SOCKADDR*)addr4, &size)) {
addr4->sin_port = htons(port);
addrs[0].size = size;
*numValidAddrs = 1;
return 0;
}
size = sizeof(*addr6);
if (!WSAStringToAddressW(UWP_STRING(&str), AF_INET6, NULL, (SOCKADDR*)addr6, &size)) {
addr6->sin6_port = htons(port);
addrs[0].size = size;
*numValidAddrs = 1;
return 0;
}
return ParseHostNew(str.ansi, port, addrs, numValidAddrs);
}
cc_result Socket_Create(cc_socket* s, cc_sockaddr* addr, cc_bool nonblocking) {
SOCKADDR* raw_addr = (SOCKADDR*)addr->data;
*s = socket(raw_addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (*s == -1) return WSAGetLastError();
if (nonblocking) {
u_long blockingMode = -1; /* non-blocking mode */
ioctlsocket(*s, FIONBIO, &blockingMode);
}
return 0;
}
cc_result Socket_Connect(cc_socket s, cc_sockaddr* addr) {
SOCKADDR* raw_addr = (SOCKADDR*)addr->data;
int res = connect(s, raw_addr, addr->size);
return res == -1 ? WSAGetLastError() : 0;
}
cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
int recvCount = recv(s, (char*)data, count, 0);
if (recvCount != -1) { *modified = recvCount; return 0; }
*modified = 0; return WSAGetLastError();
}
cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified) {
int sentCount = send(s, (const char*)data, count, 0);
if (sentCount != -1) { *modified = sentCount; return 0; }
*modified = 0; return WSAGetLastError();
}
void Socket_Close(cc_socket s) {
shutdown(s, SD_BOTH);
closesocket(s);
}
static cc_result Socket_Poll(cc_socket s, int mode, cc_bool* success) {
fd_set set;
struct timeval time = { 0 };
int selectCount;
set.fd_count = 1;
set.fd_array[0] = s;
if (mode == SOCKET_POLL_READ) {
selectCount = select(1, &set, NULL, NULL, &time);
} else {
selectCount = select(1, NULL, &set, NULL, &time);
}
if (selectCount == -1) { *success = false; return WSAGetLastError(); }
*success = set.fd_count != 0; return 0;
}
cc_result Socket_CheckReadable(cc_socket s, cc_bool* readable) {
return Socket_Poll(s, SOCKET_POLL_READ, readable);
}
cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) {
int resultSize = sizeof(cc_result);
cc_result res = Socket_Poll(s, SOCKET_POLL_WRITE, writable);
if (res || *writable) return res;
/* https://stackoverflow.com/questions/29479953/so-error-value-after-successful-socket-operation */
getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&res, &resultSize);
return res;
}
/*########################################################################################################################*
*-----------------------------------------------------Process/Module------------------------------------------------------*
*#########################################################################################################################*/
cc_bool Process_OpenSupported = true;
static cc_result Process_RawGetExePath(cc_winstring* path, int* len) {
*len = GetModuleFileNameW(NULL, UWP_STRING(path), NATIVE_STR_LEN);
path->uni[*len] = '\0';
if (*len) return 0;
return GetLastError();
}
cc_result Process_StartGame2(const cc_string* args, int numArgs) {
union STARTUPINFO_union {
STARTUPINFOW wide;
STARTUPINFOA ansi;
} si = { 0 }; // less compiler warnings this way
cc_winstring path;
cc_string argv; char argvBuffer[NATIVE_STR_LEN];
PROCESS_INFORMATION pi = { 0 };
cc_winstring raw;
cc_result res;
int len, i;
if (Platform_IsSingleProcess()) return SetGameArgs(args, numArgs);
if ((res = Process_RawGetExePath(&path, &len))) return res;
si.wide.cb = sizeof(STARTUPINFOW);
String_InitArray(argv, argvBuffer);
/* Game doesn't actually care about argv[0] */
String_AppendConst(&argv, "cc");
for (i = 0; i < numArgs; i++)
{
if (String_IndexOf(&args[i], ' ') >= 0) {
String_Format1(&argv, " \"%s\"", &args[i]);
} else {
String_Format1(&argv, " %s", &args[i]);
}
}
Platform_EncodeString(&raw, &argv);
if (!CreateProcessW(UWP_STRING(&path), UWP_STRING(&raw), NULL, NULL,
false, 0, NULL, NULL, &si.wide, &pi)) return GetLastError();
/* Don't leak memory for process return code */
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}
void Process_Exit(cc_result code) { ExitProcess(code); }
cc_result Process_StartOpen(const cc_string* args) {
cc_winstring raw;
Platform_EncodeString(&raw, args);
auto str = hstring(UWP_STRING(&raw));
auto uri = Uri(str);
auto options = Windows::System::LauncherOptions();
options.TreatAsUntrusted(true);
Windows::System::Launcher::LaunchUriAsync(uri, options);
return 0;
}
/*########################################################################################################################*
*--------------------------------------------------------Updater----------------------------------------------------------*
*#########################################################################################################################*/
#define UPDATE_TMP TEXT("CC_prev.exe")
#define UPDATE_SRC TEXT(UPDATE_FILE)
cc_bool Updater_Supported = true;
#if defined _M_IX86
const struct UpdaterInfo Updater_Info = {
"&eDirect3D 9 is recommended", 2,
{
{ "Direct3D9", "ClassiCube.exe" },
{ "OpenGL", "ClassiCube.opengl.exe" }
}
};
#elif defined _M_X64
const struct UpdaterInfo Updater_Info = {
"&eDirect3D 9 is recommended", 2,
{
{ "Direct3D9", "ClassiCube.64.exe" },
{ "OpenGL", "ClassiCube.64-opengl.exe" }
}
};
#elif defined _M_ARM64
const struct UpdaterInfo Updater_Info = { "", 1, { { "Direct3D11", "cc-arm64-d3d11.exe" } } };
#elif defined _M_ARM
const struct UpdaterInfo Updater_Info = { "", 1, { { "Direct3D11", "cc-arm32-d3d11.exe" } } };
#else
const struct UpdaterInfo Updater_Info = { "&eCompile latest source code to update", 0 };
#endif
cc_bool Updater_Clean(void) {
return DeleteFile(UPDATE_TMP) || GetLastError() == ERROR_FILE_NOT_FOUND;
}
cc_result Updater_Start(const char** action) {
cc_winstring path;
cc_result res;
int len;
*action = "Getting executable path";
if ((res = Process_RawGetExePath(&path, &len))) return res;
*action = "Moving executable to CC_prev.exe";
if (!path.uni[0]) return ERR_NOT_SUPPORTED; /* MoveFileA returns ERROR_ACCESS_DENIED on Win 9x anyways */
if (!MoveFileExW(UWP_STRING(&path), UPDATE_TMP, MOVEFILE_REPLACE_EXISTING)) return GetLastError();
*action = "Replacing executable";
if (!MoveFileExW(UPDATE_SRC, UWP_STRING(&path), MOVEFILE_REPLACE_EXISTING)) return GetLastError();
*action = "Restarting game";
return Process_StartGame2(NULL, 0);
}
cc_result Updater_GetBuildTime(cc_uint64* timestamp) {
cc_winstring path;
cc_file file;
FILETIME ft;
cc_uint64 raw;
cc_result res;
int len;
if ((res = Process_RawGetExePath(&path, &len))) return res;
if ((res = File_Open(&file, &path))) return res;
if (GetFileTime(file, NULL, NULL, &ft)) {
raw = ft.dwLowDateTime | ((cc_uint64)ft.dwHighDateTime << 32);
*timestamp = FileTime_UnixTime(raw);
} else {
res = GetLastError();
}
File_Close(file);
return res;
}
/* Don't need special execute permission on windows */
cc_result Updater_MarkExecutable(void) { return 0; }
cc_result Updater_SetNewBuildTime(cc_uint64 timestamp) {
static const cc_string path = String_FromConst(UPDATE_FILE);
cc_filepath str;
cc_file file;
FILETIME ft;
cc_uint64 raw;
cc_result res;
Platform_EncodePath(&str, &path);
res = File_OpenOrCreate(&file, &str);
if (res) return res;
raw = 10000000 * (timestamp + FILETIME_UNIX_EPOCH);
ft.dwLowDateTime = (cc_uint32)raw;
ft.dwHighDateTime = (cc_uint32)(raw >> 32);
if (!SetFileTime(file, NULL, NULL, &ft)) res = GetLastError();
File_Close(file);
return res;
}
/*########################################################################################################################*
*-------------------------------------------------------Dynamic lib-------------------------------------------------------*
*#########################################################################################################################*/
const cc_string DynamicLib_Ext = String_FromConst(".dll");
static cc_result dynamicErr;
static cc_bool loadingPlugin;
void* DynamicLib_Load2(const cc_string* path) {
return NULL;
}
void* DynamicLib_Get2(void* lib, const char* name) {
return NULL;
}
cc_bool DynamicLib_DescribeError(cc_string* dst) {
return false;
}
/*########################################################################################################################*
*--------------------------------------------------------Platform---------------------------------------------------------*
*#########################################################################################################################*/
void Platform_EncodeString(cc_winstring* dst, const cc_string* src) {
cc_unichar* uni;
char* ansi;
int i;
if (src->length > FILENAME_SIZE) Process_Abort("String too long to expand");
uni = dst->uni;
for (i = 0; i < src->length; i++)
{
*uni++ = Convert_CP437ToUnicode(src->buffer[i]);
}
*uni = '\0';
ansi = dst->ansi;
for (i = 0; i < src->length; i++)
{
*ansi++ = (char)dst->uni[i];
}
*ansi = '\0';
}
static void Platform_InitStopwatch(void) {
LARGE_INTEGER freq;
sw_highRes = QueryPerformanceFrequency(&freq);
if (sw_highRes) {
sw_freqMul = 1000 * 1000;
sw_freqDiv = freq.QuadPart;
} else { sw_freqDiv = 10; }
}
void Platform_Init(void) {
WSADATA wsaData;
cc_result res;
Platform_InitStopwatch();
heap = GetProcessHeap();
hasDebugger = IsDebuggerPresent();
AttachConsole(-1); /* ATTACH_PARENT_PROCESS */
conHandle = GetStdHandle(STD_OUTPUT_HANDLE);
if (conHandle == INVALID_HANDLE_VALUE) conHandle = NULL;
res = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (res) Logger_SysWarn(res, "starting WSA");
}
void Platform_Free(void) {
WSACleanup();
HeapDestroy(heap);
}
cc_bool Platform_DescribeError(cc_result res, cc_string* dst) {
WCHAR chars[NATIVE_STR_LEN];
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
res = FormatMessageW(flags, NULL, res, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
chars, NATIVE_STR_LEN, NULL);
if (!res) return false;
String_AppendUtf16(dst, chars, res * 2);
return true;
}
/*########################################################################################################################*
*-------------------------------------------------------Encryption--------------------------------------------------------*
*#########################################################################################################################*/
cc_result Platform_Encrypt(const void* data, int len, cc_string* dst) {
return 200;
}
cc_result Platform_Decrypt(const void* data, int len, cc_string* dst) {
return 200;
}
cc_result Platform_GetEntropy(void* data, int len) {
return ERR_NOT_SUPPORTED;
}
/*########################################################################################################################*
*-----------------------------------------------------Configuration-------------------------------------------------------*
*#########################################################################################################################*/
int Platform_GetCommandLineArgs(int argc, STRING_REF char** argv, cc_string* args) {
return GetGameArgs(args);
}
cc_result Platform_SetDefaultCurrentDirectory(int argc, char** argv) {
return 0;
}

327
misc/UWP/Window_UWP.cpp Normal file
View File

@@ -0,0 +1,327 @@
#include "../../src/Core.h"
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.ApplicationModel.Core.h>
#include <winrt/Windows.ApplicationModel.Activation.h>
#include <winrt/Windows.Devices.Input.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Graphics.Display.h>
#include <winrt/Windows.Storage.Pickers.h>
#include <winrt/Windows.System.h>
#include <winrt/Windows.UI.Core.h>
using namespace winrt;
using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::Devices::Input;
using namespace Windows::Graphics::Display;
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::UI::Core;
using namespace Windows::UI::Input;
#include "../../src/_WindowBase.h"
#include "../../src/String.h"
#include "../../src/Funcs.h"
#include "../../src/Bitmap.h"
#include "../../src/Options.h"
#include "../../src/Errors.h"
#include "../../src/Graphics.h"
#include "../../src/Game.h"
#define UWP_STRING(str) ((wchar_t*)(str)->uni)
/*########################################################################################################################*
*--------------------------------------------------Public implementation--------------------------------------------------*
*#########################################################################################################################*/
void Window_PreInit(void) {
DisplayInfo.CursorVisible = true;
}
void Window_Init(void) {
CoreWindow& window = CoreWindow::GetForCurrentThread();
Input.Sources = INPUT_SOURCE_NORMAL;
DisplayInfo.Width = 640;
DisplayInfo.Height = 480;
DisplayInfo.Depth = 32;
DisplayInfo.ScaleX = 1.0f;
DisplayInfo.ScaleY = 1.0f;
Rect bounds = window.Bounds();
WindowInfo.UIScaleX = DEFAULT_UI_SCALE_X;
WindowInfo.UIScaleY = DEFAULT_UI_SCALE_Y;
WindowInfo.Width = bounds.Width;
WindowInfo.Height = bounds.Height;
WindowInfo.Exists = true;
}
void Window_Free(void) { }
void Window_Create2D(int width, int height) { }
void Window_Create3D(int width, int height) { }
void Window_Destroy(void) {
}
void Window_SetTitle(const cc_string* title) {
}
void Clipboard_GetText(cc_string* value) {
DataPackageView content = Clipboard::GetContent();
hstring str = content.GetTextAsync().get();
}
void Clipboard_SetText(const cc_string* value) {
cc_winstring raw;
Platform_EncodeString(&raw, value);
auto str = hstring(UWP_STRING(&raw));
DataPackage package = DataPackage();
package.SetText(str);
Clipboard::SetContent(package);
}
int Window_GetWindowState(void) {
return WINDOW_STATE_NORMAL;
}
cc_result Window_EnterFullscreen(void) {
return ERR_NOT_SUPPORTED;
}
cc_result Window_ExitFullscreen(void) {
return ERR_NOT_SUPPORTED;
}
int Window_IsObscured(void) { return 0; }
void Window_Show(void) {
}
void Window_SetSize(int width, int height) {
}
void Window_RequestClose(void) {
Event_RaiseVoid(&WindowEvents.Closing);
}
void Window_ProcessEvents(float delta) {
CoreWindow& window = CoreWindow::GetForCurrentThread();
CoreDispatcher& dispatcher = window.Dispatcher();
dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
}
void Gamepads_Init(void) {
}
void Gamepads_Process(float delta) { }
static void Cursor_GetRawPos(int* x, int* y) {
CoreWindow& window = CoreWindow::GetForCurrentThread();
Point point = window.PointerPosition();
*x = point.X;
*y = point.Y;
}
void Cursor_SetPosition(int x, int y) {
CoreWindow& window = CoreWindow::GetForCurrentThread();
Point point = Point(x, y);
window.PointerPosition(point);
}
static void Cursor_DoSetVisible(cc_bool visible) {
}
static void ShowDialogCore(const char* title, const char* msg) {
}
static cc_result OpenSaveFileDialog(const cc_string* filters, FileDialogCallback callback, cc_bool load,
const char* const* fileExts, const cc_string* defaultName) {
return ERR_NOT_SUPPORTED;
//auto picker = Windows::Storage::Pickers::FileOpenPicker();
//picker.FileTypeFilter().Append(hstring(L".jpg"));
//Windows::Storage::StorageFile file = picker->PickSingleFileAsync();
}
cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) {
const char* const* fileExts = args->filters;
cc_string filters; char buffer[NATIVE_STR_LEN];
int i;
/* Filter tokens are \0 separated - e.g. "Maps (*.cw;*.dat)\0*.cw;*.dat\0 */
String_InitArray(filters, buffer);
String_Format1(&filters, "%c (", args->description);
for (i = 0; fileExts[i]; i++)
{
if (i) String_Append(&filters, ';');
String_Format1(&filters, "*%c", fileExts[i]);
}
String_Append(&filters, ')');
String_Append(&filters, '\0');
for (i = 0; fileExts[i]; i++)
{
if (i) String_Append(&filters, ';');
String_Format1(&filters, "*%c", fileExts[i]);
}
String_Append(&filters, '\0');
return OpenSaveFileDialog(&filters, args->Callback, true, fileExts, &String_Empty);
}
cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) {
const char* const* titles = args->titles;
const char* const* fileExts = args->filters;
cc_string filters; char buffer[NATIVE_STR_LEN];
int i;
/* Filter tokens are \0 separated - e.g. "Map (*.cw)\0*.cw\0 */
String_InitArray(filters, buffer);
for (i = 0; fileExts[i]; i++)
{
String_Format2(&filters, "%c (*%c)", titles[i], fileExts[i]);
String_Append(&filters, '\0');
String_Format1(&filters, "*%c", fileExts[i]);
String_Append(&filters, '\0');
}
return OpenSaveFileDialog(&filters, args->Callback, false, fileExts, &args->defaultName);
}
static GfxResourceID fb_tex, fb_vb;
static void AllocateVB(void) {
struct VertexTextured* data = (struct VertexTextured*)Gfx_RecreateAndLockVb(&fb_vb,
VERTEX_FORMAT_TEXTURED, 4);
data[0].x = -1.0f; data[0].y = -1.0f; data[0].z = 0.0f; data[0].Col = PACKEDCOL_WHITE; data[0].U = 0.0f; data[0].V = 1.0f;
data[1].x = 1.0f; data[1].y = -1.0f; data[1].z = 0.0f; data[1].Col = PACKEDCOL_WHITE; data[1].U = 1.0f; data[1].V = 1.0f;
data[2].x = 1.0f; data[2].y = 1.0f; data[2].z = 0.0f; data[2].Col = PACKEDCOL_WHITE; data[2].U = 1.0f; data[2].V = 0.0f;
data[3].x = -1.0f; data[3].y = 1.0f; data[3].z = 0.0f; data[3].Col = PACKEDCOL_WHITE; data[3].U = 0.0f; data[2].V = 0.0f;
Gfx_UnlockVb(fb_vb);
}
void Window_AllocFramebuffer(struct Bitmap* bmp, int width, int height) {
bmp->scan0 = (BitmapCol*)Mem_Alloc(width * height, BITMAPCOLOR_SIZE, "bitmap");
bmp->width = width;
bmp->height = height;
if (!Gfx.Created) Gfx_Create();
fb_tex = Gfx_AllocTexture(bmp, bmp->width, TEXTURE_FLAG_NONPOW2, false);
AllocateVB();
Game.Width = Window_Main.Width;
Game.Height = Window_Main.Height;
Gfx_OnWindowResize();
}
void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) {
struct Bitmap part;
part.scan0 = Bitmap_GetRow(bmp, r.y) + r.x;
part.width = r.width;
part.height = r.height;
Gfx_BeginFrame();
Gfx_BindIb(Gfx.DefaultIb);
Gfx_UpdateTexture(fb_tex, r.x, r.y, &part, bmp->width, false);
Gfx_LoadMatrix(MATRIX_VIEW, &Matrix_Identity);
Gfx_LoadMatrix(MATRIX_PROJ, &Matrix_Identity);
Gfx_SetDepthTest(false);
Gfx_SetAlphaTest(false);
Gfx_SetAlphaBlending(false);
Gfx_SetVertexFormat(VERTEX_FORMAT_COLOURED);
Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED);
Gfx_BindTexture(fb_tex);
Gfx_BindVb(fb_vb);
Gfx_DrawVb_IndexedTris(4);
Gfx_EndFrame();
}
void Window_FreeFramebuffer(struct Bitmap* bmp) {
Mem_Free(bmp->scan0);
Gfx_DeleteTexture(&fb_tex);
Gfx_DeleteVb(&fb_vb);
}
static cc_bool rawMouseInited, rawMouseSupported;
static void InitRawMouse(void) {
}
void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { }
void OnscreenKeyboard_SetText(const cc_string* text) { }
void OnscreenKeyboard_Close(void) { }
void Window_EnableRawMouse(void) {
DefaultEnableRawMouse();
if (!rawMouseInited) InitRawMouse();
rawMouseInited = true;
}
void Window_UpdateRawMouse(void) {
if (rawMouseSupported) {
/* handled in WM_INPUT messages */
CentreMousePosition();
} else {
DefaultUpdateRawMouse();
}
}
void Window_DisableRawMouse(void) {
DefaultDisableRawMouse();
}
struct CCApp : implements<CCApp, IFrameworkViewSource, IFrameworkView>
{
// IFrameworkViewSource interface
IFrameworkView CreateView()
{
return *this;
}
// IFrameworkView interface
void Initialize(CoreApplicationView const& view)
{
}
void Load(hstring const& entryPoint)
{
}
void Uninitialize()
{
}
void Run()
{
CoreWindow& window = CoreWindow::GetForCurrentThread();
window.Activate();
Window_Main.Handle.ptr = get_abi(window);
extern int main(int argc, char** argv);
main(0, NULL);
}
void SetWindow(CoreWindow const& win)
{
}
};
int __stdcall wWinMain(void*, void*, wchar_t** argv, int argc)
{
auto app = make<CCApp>();
CoreApplication::Run(app);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

44
misc/amiga/Makefile_68k Normal file
View File

@@ -0,0 +1,44 @@
AS=m68k-amigaos-as
CC=m68k-amigaos-gcc
CXX=m68k-amigaos-g++
CFLAGS :=-O1 -fno-math-errno -DPLAT_AMIGA -DCC_BUILD_NOFPU
TARGET := ClassiCube-68k
BUILD_DIR := build-amiga-68k
SOURCE_DIR := src
LDFLAGS :=
C_SOURCES := $(wildcard $(SOURCE_DIR)/*.c)
C_ASSEMS := $(patsubst $(SOURCE_DIR)/%.c, $(BUILD_DIR)/%.S, $(C_SOURCES))
C_OBJECTS := $(patsubst $(SOURCE_DIR)/%.c, $(BUILD_DIR)/%.o, $(C_SOURCES))
# Dependency tracking
DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.d
DEPFILES := $(C_OBJECTS:%.o=%.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
default: $(BUILD_DIR) $(TARGET).exe
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
$(TARGET).exe: $(C_OBJECTS)
$(CC) $(LDFLAGS) -o $(TARGET).exe $(C_OBJECTS)
#---------------------------------------------------------------------------------
# object generation
#---------------------------------------------------------------------------------
$(C_OBJECTS): $(BUILD_DIR)/%.o : $(BUILD_DIR)/%.S
$(AS) $< -o $@
$(C_ASSEMS): $(BUILD_DIR)/%.S : $(SOURCE_DIR)/%.c
$(CC) $(CFLAGS) $(DEPFLAGS) -S -c $< -o $@
# Dependency tracking
$(DEPFILES):
include $(wildcard $(DEPFILES))

41
misc/bitmap_font_gen.cs Normal file
View File

@@ -0,0 +1,41 @@
void Main()
{
Console.WriteLine("static cc_uint8 font_bitmap[][8] = {");
using (Bitmap bmp = new Bitmap(@"C:\classicube-dev\default.png"))
{
for (int CY = 0; CY < 16; CY++)
for (int CX = 0; CX < 16; CX++)
DecodeTile(bmp, CX, CY);
}
Console.WriteLine("}");
}
static void DecodeTile(Bitmap bmp, int cx, int cy) {
int c = (cy << 4) | cx;
if (c <= 32 || c >= 127) return;
int X = cx * 8, Y = cy * 8;
Console.Write("\t{ ");
for (int y = Y; y < Y + 8; y++) {
uint mask = 0;
int shift = 0;
for (int x = X; x < X + 8; x++, shift++) {
Color P = bmp.GetPixel(x, y);
if (P.A == 0) {
mask |= 0u << shift;
} else if (P.R == 255 && P.G == 255 && P.B == 255 && P.A == 255) {
mask |= 1u << shift;
} else {
throw new InvalidOperationException("unsupported colour" + P);
}
}
string suffix = y == Y + 7 ? " " : ",";
Console.Write("0x" + mask.ToString("X2") + suffix);
}
Console.WriteLine("}, /* " + (char)c + " */");
}

View File

@@ -0,0 +1,65 @@
#!/bin/bash
# This is similar to buildbot.sh but builds plugins for the game instead
# Some variables must be set before invoking this script. See buildtestplugin.sh
cd $ROOT
echo $(pwd)
FILES=$(find . -type f -name "*.c" | tr '\n' ' ')
FLAGS="-shared -fPIC -O1 -s -std=c99"
echo $FILES
# ----------------------------- compile linux
NIX32_CC="gcc -m32"
NIX64_CC="gcc -m64"
NIX_FLAGS="-nostartfiles -Wl,--entry=0"
echo "Compiling linux32.."
$NIX32_CC $FILES -I ~/client/src/ -I ./src/ -o ${PLUGIN}_nix32.so $FLAGS $NIX_FLAGS
echo "Compiling linux64.."
$NIX64_CC $FILES -I ~/client/src/ -I ./src/ -o ${PLUGIN}_nix64.so $FLAGS $NIX_FLAGS
# ----------------------------- compile macOS
MAC32_CC=~/osx/target/bin/o32-clang
MAC64_CC=~/osx/target/bin/o64-clang
MAC_FLAGS="-undefined dynamic_lookup"
echo "Compiling mac32.."
$MAC32_CC $FILES -I ~/client/src/ -I ./src/ -o ${PLUGIN}_mac32.dylib $FLAGS $MAC_FLAGS
echo "Compiling mac64.."
$MAC64_CC $FILES -I ~/client/src/ -I ./src/ -o ${PLUGIN}_mac64.dylib $FLAGS $MAC_FLAGS
# ----------------------------- compile Windows
WIN32_CC=i686-w64-mingw32-gcc
WIN64_CC=x86_64-w64-mingw32-gcc
# TODO: Figure out why we sometimes need this with mingw
# If we don't include nostart files for some plugins, get a
# ertr000001.o:(.rdata+0x0): undefined reference to `_pei386_runtime_relocator'
# Seems to happen if you use exported variables from the game
if [ -z "$LITE_MODE" ]; then
WIN_FLAGS=""
else
WIN_FLAGS="-nostartfiles -Wl,--entry=0"
fi
# NOTE: You also need to install 'mingw-w64-tools' package for gendef
echo "Compiling win32"
rm ClassiCube.exe ClassiCube.def
cp ~/client/src/cc-w32-d3d.exe ClassiCube.exe
gendef ClassiCube.exe
i686-w64-mingw32-dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe
$WIN32_CC $FILES -I ~/client/src/ -I ./src/ -o ${PLUGIN}_win32.dll $FLAGS $WIN_FLAGS -L . -lClassiCube
echo "Compiling win64"
rm ClassiCube.exe ClassiCube.def
cp ~/client/src/cc-w64-d3d.exe ClassiCube.exe
gendef ClassiCube.exe
x86_64-w64-mingw32-dlltool -d ClassiCube.def -l libClassiCube.a -D ClassiCube.exe
$WIN64_CC $FILES -I ~/client/src/ -I ./src/ -o ${PLUGIN}_win64.dll $FLAGS $WIN_FLAGS -L . -lClassiCube
# ----------------------------- compile raspberry pi
RPI_CC=~/rpi/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-gcc-4.8.3
RPI_FLAGS="-nostartfiles -Wl,--entry=0"
echo "Compiling rpi"
$RPI_CC $FILES -I ~/client/src/ -I ./src/ -o ${PLUGIN}_rpi.so $FLAGS $RPI_FLAGS

View File

@@ -0,0 +1,4 @@
#!/bin/bash
ROOT=~/plugins/test/
PLUGIN=test
source ./buildbot_plugin.sh

View File

@@ -0,0 +1,6 @@
This folder contains build scripts for automatically compiling ClassiCube
|File|Description|
|--------|-------|
|buildbot_plugin.sh | Compiles specified plugin for various platforms |
|buildtestplugin.sh | Example script for how to use buildbot_plugin.sh |

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,34 @@
-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----

397
misc/certs/certs.h Normal file
View File

@@ -0,0 +1,397 @@
// This file includes the following root certificates:
// - DigiCert Global Root (dropbox.com)
// - DigiCert Global Root G2 (resources.download.minecraft.net)
// - ISRG Root X1 (catbox.moe)
// - ISRG Root X2 (123dmwm.com, garbage.loan)
// - Baltimore CyberTrust Root (old classicube.net)
// - USERTrust RSA (imgur.com)
// - Google Trust Services Root R4 (classicube.net)
// Generated using "brssl -ta [cert 1] [cert 2].." from BearSSL
static const unsigned char TA0_DN[] = {
0x30, 0x61, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x0C, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49,
0x6E, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13,
0x10, 0x77, 0x77, 0x77, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72,
0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x20, 0x30, 0x1E, 0x06, 0x03, 0x55,
0x04, 0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
0x20, 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x20, 0x52, 0x6F, 0x6F, 0x74,
0x20, 0x43, 0x41
};
static const unsigned char TA0_RSA_N[] = {
0xE2, 0x3B, 0xE1, 0x11, 0x72, 0xDE, 0xA8, 0xA4, 0xD3, 0xA3, 0x57, 0xAA,
0x50, 0xA2, 0x8F, 0x0B, 0x77, 0x90, 0xC9, 0xA2, 0xA5, 0xEE, 0x12, 0xCE,
0x96, 0x5B, 0x01, 0x09, 0x20, 0xCC, 0x01, 0x93, 0xA7, 0x4E, 0x30, 0xB7,
0x53, 0xF7, 0x43, 0xC4, 0x69, 0x00, 0x57, 0x9D, 0xE2, 0x8D, 0x22, 0xDD,
0x87, 0x06, 0x40, 0x00, 0x81, 0x09, 0xCE, 0xCE, 0x1B, 0x83, 0xBF, 0xDF,
0xCD, 0x3B, 0x71, 0x46, 0xE2, 0xD6, 0x66, 0xC7, 0x05, 0xB3, 0x76, 0x27,
0x16, 0x8F, 0x7B, 0x9E, 0x1E, 0x95, 0x7D, 0xEE, 0xB7, 0x48, 0xA3, 0x08,
0xDA, 0xD6, 0xAF, 0x7A, 0x0C, 0x39, 0x06, 0x65, 0x7F, 0x4A, 0x5D, 0x1F,
0xBC, 0x17, 0xF8, 0xAB, 0xBE, 0xEE, 0x28, 0xD7, 0x74, 0x7F, 0x7A, 0x78,
0x99, 0x59, 0x85, 0x68, 0x6E, 0x5C, 0x23, 0x32, 0x4B, 0xBF, 0x4E, 0xC0,
0xE8, 0x5A, 0x6D, 0xE3, 0x70, 0xBF, 0x77, 0x10, 0xBF, 0xFC, 0x01, 0xF6,
0x85, 0xD9, 0xA8, 0x44, 0x10, 0x58, 0x32, 0xA9, 0x75, 0x18, 0xD5, 0xD1,
0xA2, 0xBE, 0x47, 0xE2, 0x27, 0x6A, 0xF4, 0x9A, 0x33, 0xF8, 0x49, 0x08,
0x60, 0x8B, 0xD4, 0x5F, 0xB4, 0x3A, 0x84, 0xBF, 0xA1, 0xAA, 0x4A, 0x4C,
0x7D, 0x3E, 0xCF, 0x4F, 0x5F, 0x6C, 0x76, 0x5E, 0xA0, 0x4B, 0x37, 0x91,
0x9E, 0xDC, 0x22, 0xE6, 0x6D, 0xCE, 0x14, 0x1A, 0x8E, 0x6A, 0xCB, 0xFE,
0xCD, 0xB3, 0x14, 0x64, 0x17, 0xC7, 0x5B, 0x29, 0x9E, 0x32, 0xBF, 0xF2,
0xEE, 0xFA, 0xD3, 0x0B, 0x42, 0xD4, 0xAB, 0xB7, 0x41, 0x32, 0xDA, 0x0C,
0xD4, 0xEF, 0xF8, 0x81, 0xD5, 0xBB, 0x8D, 0x58, 0x3F, 0xB5, 0x1B, 0xE8,
0x49, 0x28, 0xA2, 0x70, 0xDA, 0x31, 0x04, 0xDD, 0xF7, 0xB2, 0x16, 0xF2,
0x4C, 0x0A, 0x4E, 0x07, 0xA8, 0xED, 0x4A, 0x3D, 0x5E, 0xB5, 0x7F, 0xA3,
0x90, 0xC3, 0xAF, 0x27
};
static const unsigned char TA0_RSA_E[] = {
0x01, 0x00, 0x01
};
static const unsigned char TA1_DN[] = {
0x30, 0x61, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x0C, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74, 0x20, 0x49,
0x6E, 0x63, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13,
0x10, 0x77, 0x77, 0x77, 0x2E, 0x64, 0x69, 0x67, 0x69, 0x63, 0x65, 0x72,
0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x31, 0x20, 0x30, 0x1E, 0x06, 0x03, 0x55,
0x04, 0x03, 0x13, 0x17, 0x44, 0x69, 0x67, 0x69, 0x43, 0x65, 0x72, 0x74,
0x20, 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x20, 0x52, 0x6F, 0x6F, 0x74,
0x20, 0x47, 0x32
};
static const unsigned char TA1_RSA_N[] = {
0xBB, 0x37, 0xCD, 0x34, 0xDC, 0x7B, 0x6B, 0xC9, 0xB2, 0x68, 0x90, 0xAD,
0x4A, 0x75, 0xFF, 0x46, 0xBA, 0x21, 0x0A, 0x08, 0x8D, 0xF5, 0x19, 0x54,
0xC9, 0xFB, 0x88, 0xDB, 0xF3, 0xAE, 0xF2, 0x3A, 0x89, 0x91, 0x3C, 0x7A,
0xE6, 0xAB, 0x06, 0x1A, 0x6B, 0xCF, 0xAC, 0x2D, 0xE8, 0x5E, 0x09, 0x24,
0x44, 0xBA, 0x62, 0x9A, 0x7E, 0xD6, 0xA3, 0xA8, 0x7E, 0xE0, 0x54, 0x75,
0x20, 0x05, 0xAC, 0x50, 0xB7, 0x9C, 0x63, 0x1A, 0x6C, 0x30, 0xDC, 0xDA,
0x1F, 0x19, 0xB1, 0xD7, 0x1E, 0xDE, 0xFD, 0xD7, 0xE0, 0xCB, 0x94, 0x83,
0x37, 0xAE, 0xEC, 0x1F, 0x43, 0x4E, 0xDD, 0x7B, 0x2C, 0xD2, 0xBD, 0x2E,
0xA5, 0x2F, 0xE4, 0xA9, 0xB8, 0xAD, 0x3A, 0xD4, 0x99, 0xA4, 0xB6, 0x25,
0xE9, 0x9B, 0x6B, 0x00, 0x60, 0x92, 0x60, 0xFF, 0x4F, 0x21, 0x49, 0x18,
0xF7, 0x67, 0x90, 0xAB, 0x61, 0x06, 0x9C, 0x8F, 0xF2, 0xBA, 0xE9, 0xB4,
0xE9, 0x92, 0x32, 0x6B, 0xB5, 0xF3, 0x57, 0xE8, 0x5D, 0x1B, 0xCD, 0x8C,
0x1D, 0xAB, 0x95, 0x04, 0x95, 0x49, 0xF3, 0x35, 0x2D, 0x96, 0xE3, 0x49,
0x6D, 0xDD, 0x77, 0xE3, 0xFB, 0x49, 0x4B, 0xB4, 0xAC, 0x55, 0x07, 0xA9,
0x8F, 0x95, 0xB3, 0xB4, 0x23, 0xBB, 0x4C, 0x6D, 0x45, 0xF0, 0xF6, 0xA9,
0xB2, 0x95, 0x30, 0xB4, 0xFD, 0x4C, 0x55, 0x8C, 0x27, 0x4A, 0x57, 0x14,
0x7C, 0x82, 0x9D, 0xCD, 0x73, 0x92, 0xD3, 0x16, 0x4A, 0x06, 0x0C, 0x8C,
0x50, 0xD1, 0x8F, 0x1E, 0x09, 0xBE, 0x17, 0xA1, 0xE6, 0x21, 0xCA, 0xFD,
0x83, 0xE5, 0x10, 0xBC, 0x83, 0xA5, 0x0A, 0xC4, 0x67, 0x28, 0xF6, 0x73,
0x14, 0x14, 0x3D, 0x46, 0x76, 0xC3, 0x87, 0x14, 0x89, 0x21, 0x34, 0x4D,
0xAF, 0x0F, 0x45, 0x0C, 0xA6, 0x49, 0xA1, 0xBA, 0xBB, 0x9C, 0xC5, 0xB1,
0x33, 0x83, 0x29, 0x85
};
static const unsigned char TA1_RSA_E[] = {
0x01, 0x00, 0x01
};
static const unsigned char TA2_DN[] = {
0x30, 0x4F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 0x74, 0x20, 0x53,
0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65,
0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6F, 0x75, 0x70, 0x31, 0x15,
0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0C, 0x49, 0x53, 0x52,
0x47, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x58, 0x31
};
static const unsigned char TA2_RSA_N[] = {
0xAD, 0xE8, 0x24, 0x73, 0xF4, 0x14, 0x37, 0xF3, 0x9B, 0x9E, 0x2B, 0x57,
0x28, 0x1C, 0x87, 0xBE, 0xDC, 0xB7, 0xDF, 0x38, 0x90, 0x8C, 0x6E, 0x3C,
0xE6, 0x57, 0xA0, 0x78, 0xF7, 0x75, 0xC2, 0xA2, 0xFE, 0xF5, 0x6A, 0x6E,
0xF6, 0x00, 0x4F, 0x28, 0xDB, 0xDE, 0x68, 0x86, 0x6C, 0x44, 0x93, 0xB6,
0xB1, 0x63, 0xFD, 0x14, 0x12, 0x6B, 0xBF, 0x1F, 0xD2, 0xEA, 0x31, 0x9B,
0x21, 0x7E, 0xD1, 0x33, 0x3C, 0xBA, 0x48, 0xF5, 0xDD, 0x79, 0xDF, 0xB3,
0xB8, 0xFF, 0x12, 0xF1, 0x21, 0x9A, 0x4B, 0xC1, 0x8A, 0x86, 0x71, 0x69,
0x4A, 0x66, 0x66, 0x6C, 0x8F, 0x7E, 0x3C, 0x70, 0xBF, 0xAD, 0x29, 0x22,
0x06, 0xF3, 0xE4, 0xC0, 0xE6, 0x80, 0xAE, 0xE2, 0x4B, 0x8F, 0xB7, 0x99,
0x7E, 0x94, 0x03, 0x9F, 0xD3, 0x47, 0x97, 0x7C, 0x99, 0x48, 0x23, 0x53,
0xE8, 0x38, 0xAE, 0x4F, 0x0A, 0x6F, 0x83, 0x2E, 0xD1, 0x49, 0x57, 0x8C,
0x80, 0x74, 0xB6, 0xDA, 0x2F, 0xD0, 0x38, 0x8D, 0x7B, 0x03, 0x70, 0x21,
0x1B, 0x75, 0xF2, 0x30, 0x3C, 0xFA, 0x8F, 0xAE, 0xDD, 0xDA, 0x63, 0xAB,
0xEB, 0x16, 0x4F, 0xC2, 0x8E, 0x11, 0x4B, 0x7E, 0xCF, 0x0B, 0xE8, 0xFF,
0xB5, 0x77, 0x2E, 0xF4, 0xB2, 0x7B, 0x4A, 0xE0, 0x4C, 0x12, 0x25, 0x0C,
0x70, 0x8D, 0x03, 0x29, 0xA0, 0xE1, 0x53, 0x24, 0xEC, 0x13, 0xD9, 0xEE,
0x19, 0xBF, 0x10, 0xB3, 0x4A, 0x8C, 0x3F, 0x89, 0xA3, 0x61, 0x51, 0xDE,
0xAC, 0x87, 0x07, 0x94, 0xF4, 0x63, 0x71, 0xEC, 0x2E, 0xE2, 0x6F, 0x5B,
0x98, 0x81, 0xE1, 0x89, 0x5C, 0x34, 0x79, 0x6C, 0x76, 0xEF, 0x3B, 0x90,
0x62, 0x79, 0xE6, 0xDB, 0xA4, 0x9A, 0x2F, 0x26, 0xC5, 0xD0, 0x10, 0xE1,
0x0E, 0xDE, 0xD9, 0x10, 0x8E, 0x16, 0xFB, 0xB7, 0xF7, 0xA8, 0xF7, 0xC7,
0xE5, 0x02, 0x07, 0x98, 0x8F, 0x36, 0x08, 0x95, 0xE7, 0xE2, 0x37, 0x96,
0x0D, 0x36, 0x75, 0x9E, 0xFB, 0x0E, 0x72, 0xB1, 0x1D, 0x9B, 0xBC, 0x03,
0xF9, 0x49, 0x05, 0xD8, 0x81, 0xDD, 0x05, 0xB4, 0x2A, 0xD6, 0x41, 0xE9,
0xAC, 0x01, 0x76, 0x95, 0x0A, 0x0F, 0xD8, 0xDF, 0xD5, 0xBD, 0x12, 0x1F,
0x35, 0x2F, 0x28, 0x17, 0x6C, 0xD2, 0x98, 0xC1, 0xA8, 0x09, 0x64, 0x77,
0x6E, 0x47, 0x37, 0xBA, 0xCE, 0xAC, 0x59, 0x5E, 0x68, 0x9D, 0x7F, 0x72,
0xD6, 0x89, 0xC5, 0x06, 0x41, 0x29, 0x3E, 0x59, 0x3E, 0xDD, 0x26, 0xF5,
0x24, 0xC9, 0x11, 0xA7, 0x5A, 0xA3, 0x4C, 0x40, 0x1F, 0x46, 0xA1, 0x99,
0xB5, 0xA7, 0x3A, 0x51, 0x6E, 0x86, 0x3B, 0x9E, 0x7D, 0x72, 0xA7, 0x12,
0x05, 0x78, 0x59, 0xED, 0x3E, 0x51, 0x78, 0x15, 0x0B, 0x03, 0x8F, 0x8D,
0xD0, 0x2F, 0x05, 0xB2, 0x3E, 0x7B, 0x4A, 0x1C, 0x4B, 0x73, 0x05, 0x12,
0xFC, 0xC6, 0xEA, 0xE0, 0x50, 0x13, 0x7C, 0x43, 0x93, 0x74, 0xB3, 0xCA,
0x74, 0xE7, 0x8E, 0x1F, 0x01, 0x08, 0xD0, 0x30, 0xD4, 0x5B, 0x71, 0x36,
0xB4, 0x07, 0xBA, 0xC1, 0x30, 0x30, 0x5C, 0x48, 0xB7, 0x82, 0x3B, 0x98,
0xA6, 0x7D, 0x60, 0x8A, 0xA2, 0xA3, 0x29, 0x82, 0xCC, 0xBA, 0xBD, 0x83,
0x04, 0x1B, 0xA2, 0x83, 0x03, 0x41, 0xA1, 0xD6, 0x05, 0xF1, 0x1B, 0xC2,
0xB6, 0xF0, 0xA8, 0x7C, 0x86, 0x3B, 0x46, 0xA8, 0x48, 0x2A, 0x88, 0xDC,
0x76, 0x9A, 0x76, 0xBF, 0x1F, 0x6A, 0xA5, 0x3D, 0x19, 0x8F, 0xEB, 0x38,
0xF3, 0x64, 0xDE, 0xC8, 0x2B, 0x0D, 0x0A, 0x28, 0xFF, 0xF7, 0xDB, 0xE2,
0x15, 0x42, 0xD4, 0x22, 0xD0, 0x27, 0x5D, 0xE1, 0x79, 0xFE, 0x18, 0xE7,
0x70, 0x88, 0xAD, 0x4E, 0xE6, 0xD9, 0x8B, 0x3A, 0xC6, 0xDD, 0x27, 0x51,
0x6E, 0xFF, 0xBC, 0x64, 0xF5, 0x33, 0x43, 0x4F
};
static const unsigned char TA2_RSA_E[] = {
0x01, 0x00, 0x01
};
static const unsigned char TA3_DN[] = {
0x30, 0x4F, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x29, 0x30, 0x27, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x20, 0x49, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x65, 0x74, 0x20, 0x53,
0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x20, 0x52, 0x65, 0x73, 0x65,
0x61, 0x72, 0x63, 0x68, 0x20, 0x47, 0x72, 0x6F, 0x75, 0x70, 0x31, 0x15,
0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0C, 0x49, 0x53, 0x52,
0x47, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x58, 0x32
};
static const unsigned char TA3_EC_Q[] = {
0x04, 0xCD, 0x9B, 0xD5, 0x9F, 0x80, 0x83, 0x0A, 0xEC, 0x09, 0x4A, 0xF3,
0x16, 0x4A, 0x3E, 0x5C, 0xCF, 0x77, 0xAC, 0xDE, 0x67, 0x05, 0x0D, 0x1D,
0x07, 0xB6, 0xDC, 0x16, 0xFB, 0x5A, 0x8B, 0x14, 0xDB, 0xE2, 0x71, 0x60,
0xC4, 0xBA, 0x45, 0x95, 0x11, 0x89, 0x8E, 0xEA, 0x06, 0xDF, 0xF7, 0x2A,
0x16, 0x1C, 0xA4, 0xB9, 0xC5, 0xC5, 0x32, 0xE0, 0x03, 0xE0, 0x1E, 0x82,
0x18, 0x38, 0x8B, 0xD7, 0x45, 0xD8, 0x0A, 0x6A, 0x6E, 0xE6, 0x00, 0x77,
0xFB, 0x02, 0x51, 0x7D, 0x22, 0xD8, 0x0A, 0x6E, 0x9A, 0x5B, 0x77, 0xDF,
0xF0, 0xFA, 0x41, 0xEC, 0x39, 0xDC, 0x75, 0xCA, 0x68, 0x07, 0x0C, 0x1F,
0xEA
};
static const unsigned char TA4_DN[] = {
0x30, 0x5A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x49, 0x45, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x09, 0x42, 0x61, 0x6C, 0x74, 0x69, 0x6D, 0x6F, 0x72, 0x65, 0x31,
0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13, 0x0A, 0x43, 0x79,
0x62, 0x65, 0x72, 0x54, 0x72, 0x75, 0x73, 0x74, 0x31, 0x22, 0x30, 0x20,
0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x19, 0x42, 0x61, 0x6C, 0x74, 0x69,
0x6D, 0x6F, 0x72, 0x65, 0x20, 0x43, 0x79, 0x62, 0x65, 0x72, 0x54, 0x72,
0x75, 0x73, 0x74, 0x20, 0x52, 0x6F, 0x6F, 0x74
};
static const unsigned char TA4_RSA_N[] = {
0xA3, 0x04, 0xBB, 0x22, 0xAB, 0x98, 0x3D, 0x57, 0xE8, 0x26, 0x72, 0x9A,
0xB5, 0x79, 0xD4, 0x29, 0xE2, 0xE1, 0xE8, 0x95, 0x80, 0xB1, 0xB0, 0xE3,
0x5B, 0x8E, 0x2B, 0x29, 0x9A, 0x64, 0xDF, 0xA1, 0x5D, 0xED, 0xB0, 0x09,
0x05, 0x6D, 0xDB, 0x28, 0x2E, 0xCE, 0x62, 0xA2, 0x62, 0xFE, 0xB4, 0x88,
0xDA, 0x12, 0xEB, 0x38, 0xEB, 0x21, 0x9D, 0xC0, 0x41, 0x2B, 0x01, 0x52,
0x7B, 0x88, 0x77, 0xD3, 0x1C, 0x8F, 0xC7, 0xBA, 0xB9, 0x88, 0xB5, 0x6A,
0x09, 0xE7, 0x73, 0xE8, 0x11, 0x40, 0xA7, 0xD1, 0xCC, 0xCA, 0x62, 0x8D,
0x2D, 0xE5, 0x8F, 0x0B, 0xA6, 0x50, 0xD2, 0xA8, 0x50, 0xC3, 0x28, 0xEA,
0xF5, 0xAB, 0x25, 0x87, 0x8A, 0x9A, 0x96, 0x1C, 0xA9, 0x67, 0xB8, 0x3F,
0x0C, 0xD5, 0xF7, 0xF9, 0x52, 0x13, 0x2F, 0xC2, 0x1B, 0xD5, 0x70, 0x70,
0xF0, 0x8F, 0xC0, 0x12, 0xCA, 0x06, 0xCB, 0x9A, 0xE1, 0xD9, 0xCA, 0x33,
0x7A, 0x77, 0xD6, 0xF8, 0xEC, 0xB9, 0xF1, 0x68, 0x44, 0x42, 0x48, 0x13,
0xD2, 0xC0, 0xC2, 0xA4, 0xAE, 0x5E, 0x60, 0xFE, 0xB6, 0xA6, 0x05, 0xFC,
0xB4, 0xDD, 0x07, 0x59, 0x02, 0xD4, 0x59, 0x18, 0x98, 0x63, 0xF5, 0xA5,
0x63, 0xE0, 0x90, 0x0C, 0x7D, 0x5D, 0xB2, 0x06, 0x7A, 0xF3, 0x85, 0xEA,
0xEB, 0xD4, 0x03, 0xAE, 0x5E, 0x84, 0x3E, 0x5F, 0xFF, 0x15, 0xED, 0x69,
0xBC, 0xF9, 0x39, 0x36, 0x72, 0x75, 0xCF, 0x77, 0x52, 0x4D, 0xF3, 0xC9,
0x90, 0x2C, 0xB9, 0x3D, 0xE5, 0xC9, 0x23, 0x53, 0x3F, 0x1F, 0x24, 0x98,
0x21, 0x5C, 0x07, 0x99, 0x29, 0xBD, 0xC6, 0x3A, 0xEC, 0xE7, 0x6E, 0x86,
0x3A, 0x6B, 0x97, 0x74, 0x63, 0x33, 0xBD, 0x68, 0x18, 0x31, 0xF0, 0x78,
0x8D, 0x76, 0xBF, 0xFC, 0x9E, 0x8E, 0x5D, 0x2A, 0x86, 0xA7, 0x4D, 0x90,
0xDC, 0x27, 0x1A, 0x39
};
static const unsigned char TA4_RSA_E[] = {
0x01, 0x00, 0x01
};
static const unsigned char TA5_DN[] = {
0x30, 0x81, 0x88, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
0x08, 0x13, 0x0A, 0x4E, 0x65, 0x77, 0x20, 0x4A, 0x65, 0x72, 0x73, 0x65,
0x79, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0B,
0x4A, 0x65, 0x72, 0x73, 0x65, 0x79, 0x20, 0x43, 0x69, 0x74, 0x79, 0x31,
0x1E, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x15, 0x54, 0x68,
0x65, 0x20, 0x55, 0x53, 0x45, 0x52, 0x54, 0x52, 0x55, 0x53, 0x54, 0x20,
0x4E, 0x65, 0x74, 0x77, 0x6F, 0x72, 0x6B, 0x31, 0x2E, 0x30, 0x2C, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x55, 0x53, 0x45, 0x52, 0x54, 0x72,
0x75, 0x73, 0x74, 0x20, 0x52, 0x53, 0x41, 0x20, 0x43, 0x65, 0x72, 0x74,
0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x20, 0x41, 0x75,
0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79
};
static const unsigned char TA5_RSA_N[] = {
0x80, 0x12, 0x65, 0x17, 0x36, 0x0E, 0xC3, 0xDB, 0x08, 0xB3, 0xD0, 0xAC,
0x57, 0x0D, 0x76, 0xED, 0xCD, 0x27, 0xD3, 0x4C, 0xAD, 0x50, 0x83, 0x61,
0xE2, 0xAA, 0x20, 0x4D, 0x09, 0x2D, 0x64, 0x09, 0xDC, 0xCE, 0x89, 0x9F,
0xCC, 0x3D, 0xA9, 0xEC, 0xF6, 0xCF, 0xC1, 0xDC, 0xF1, 0xD3, 0xB1, 0xD6,
0x7B, 0x37, 0x28, 0x11, 0x2B, 0x47, 0xDA, 0x39, 0xC6, 0xBC, 0x3A, 0x19,
0xB4, 0x5F, 0xA6, 0xBD, 0x7D, 0x9D, 0xA3, 0x63, 0x42, 0xB6, 0x76, 0xF2,
0xA9, 0x3B, 0x2B, 0x91, 0xF8, 0xE2, 0x6F, 0xD0, 0xEC, 0x16, 0x20, 0x90,
0x09, 0x3E, 0xE2, 0xE8, 0x74, 0xC9, 0x18, 0xB4, 0x91, 0xD4, 0x62, 0x64,
0xDB, 0x7F, 0xA3, 0x06, 0xF1, 0x88, 0x18, 0x6A, 0x90, 0x22, 0x3C, 0xBC,
0xFE, 0x13, 0xF0, 0x87, 0x14, 0x7B, 0xF6, 0xE4, 0x1F, 0x8E, 0xD4, 0xE4,
0x51, 0xC6, 0x11, 0x67, 0x46, 0x08, 0x51, 0xCB, 0x86, 0x14, 0x54, 0x3F,
0xBC, 0x33, 0xFE, 0x7E, 0x6C, 0x9C, 0xFF, 0x16, 0x9D, 0x18, 0xBD, 0x51,
0x8E, 0x35, 0xA6, 0xA7, 0x66, 0xC8, 0x72, 0x67, 0xDB, 0x21, 0x66, 0xB1,
0xD4, 0x9B, 0x78, 0x03, 0xC0, 0x50, 0x3A, 0xE8, 0xCC, 0xF0, 0xDC, 0xBC,
0x9E, 0x4C, 0xFE, 0xAF, 0x05, 0x96, 0x35, 0x1F, 0x57, 0x5A, 0xB7, 0xFF,
0xCE, 0xF9, 0x3D, 0xB7, 0x2C, 0xB6, 0xF6, 0x54, 0xDD, 0xC8, 0xE7, 0x12,
0x3A, 0x4D, 0xAE, 0x4C, 0x8A, 0xB7, 0x5C, 0x9A, 0xB4, 0xB7, 0x20, 0x3D,
0xCA, 0x7F, 0x22, 0x34, 0xAE, 0x7E, 0x3B, 0x68, 0x66, 0x01, 0x44, 0xE7,
0x01, 0x4E, 0x46, 0x53, 0x9B, 0x33, 0x60, 0xF7, 0x94, 0xBE, 0x53, 0x37,
0x90, 0x73, 0x43, 0xF3, 0x32, 0xC3, 0x53, 0xEF, 0xDB, 0xAA, 0xFE, 0x74,
0x4E, 0x69, 0xC7, 0x6B, 0x8C, 0x60, 0x93, 0xDE, 0xC4, 0xC7, 0x0C, 0xDF,
0xE1, 0x32, 0xAE, 0xCC, 0x93, 0x3B, 0x51, 0x78, 0x95, 0x67, 0x8B, 0xEE,
0x3D, 0x56, 0xFE, 0x0C, 0xD0, 0x69, 0x0F, 0x1B, 0x0F, 0xF3, 0x25, 0x26,
0x6B, 0x33, 0x6D, 0xF7, 0x6E, 0x47, 0xFA, 0x73, 0x43, 0xE5, 0x7E, 0x0E,
0xA5, 0x66, 0xB1, 0x29, 0x7C, 0x32, 0x84, 0x63, 0x55, 0x89, 0xC4, 0x0D,
0xC1, 0x93, 0x54, 0x30, 0x19, 0x13, 0xAC, 0xD3, 0x7D, 0x37, 0xA7, 0xEB,
0x5D, 0x3A, 0x6C, 0x35, 0x5C, 0xDB, 0x41, 0xD7, 0x12, 0xDA, 0xA9, 0x49,
0x0B, 0xDF, 0xD8, 0x80, 0x8A, 0x09, 0x93, 0x62, 0x8E, 0xB5, 0x66, 0xCF,
0x25, 0x88, 0xCD, 0x84, 0xB8, 0xB1, 0x3F, 0xA4, 0x39, 0x0F, 0xD9, 0x02,
0x9E, 0xEB, 0x12, 0x4C, 0x95, 0x7C, 0xF3, 0x6B, 0x05, 0xA9, 0x5E, 0x16,
0x83, 0xCC, 0xB8, 0x67, 0xE2, 0xE8, 0x13, 0x9D, 0xCC, 0x5B, 0x82, 0xD3,
0x4C, 0xB3, 0xED, 0x5B, 0xFF, 0xDE, 0xE5, 0x73, 0xAC, 0x23, 0x3B, 0x2D,
0x00, 0xBF, 0x35, 0x55, 0x74, 0x09, 0x49, 0xD8, 0x49, 0x58, 0x1A, 0x7F,
0x92, 0x36, 0xE6, 0x51, 0x92, 0x0E, 0xF3, 0x26, 0x7D, 0x1C, 0x4D, 0x17,
0xBC, 0xC9, 0xEC, 0x43, 0x26, 0xD0, 0xBF, 0x41, 0x5F, 0x40, 0xA9, 0x44,
0x44, 0xF4, 0x99, 0xE7, 0x57, 0x87, 0x9E, 0x50, 0x1F, 0x57, 0x54, 0xA8,
0x3E, 0xFD, 0x74, 0x63, 0x2F, 0xB1, 0x50, 0x65, 0x09, 0xE6, 0x58, 0x42,
0x2E, 0x43, 0x1A, 0x4C, 0xB4, 0xF0, 0x25, 0x47, 0x59, 0xFA, 0x04, 0x1E,
0x93, 0xD4, 0x26, 0x46, 0x4A, 0x50, 0x81, 0xB2, 0xDE, 0xBE, 0x78, 0xB7,
0xFC, 0x67, 0x15, 0xE1, 0xC9, 0x57, 0x84, 0x1E, 0x0F, 0x63, 0xD6, 0xE9,
0x62, 0xBA, 0xD6, 0x5F, 0x55, 0x2E, 0xEA, 0x5C, 0xC6, 0x28, 0x08, 0x04,
0x25, 0x39, 0xB8, 0x0E, 0x2B, 0xA9, 0xF2, 0x4C, 0x97, 0x1C, 0x07, 0x3F,
0x0D, 0x52, 0xF5, 0xED, 0xEF, 0x2F, 0x82, 0x0F
};
static const unsigned char TA5_RSA_E[] = {
0x01, 0x00, 0x01
};
static const unsigned char TA6_DN[] = {
0x30, 0x47, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x19, 0x47, 0x6F, 0x6F, 0x67, 0x6C, 0x65, 0x20, 0x54, 0x72, 0x75,
0x73, 0x74, 0x20, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20,
0x4C, 0x4C, 0x43, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x04, 0x03,
0x13, 0x0B, 0x47, 0x54, 0x53, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x52,
0x34
};
static const unsigned char TA6_EC_Q[] = {
0x04, 0xF3, 0x74, 0x73, 0xA7, 0x68, 0x8B, 0x60, 0xAE, 0x43, 0xB8, 0x35,
0xC5, 0x81, 0x30, 0x7B, 0x4B, 0x49, 0x9D, 0xFB, 0xC1, 0x61, 0xCE, 0xE6,
0xDE, 0x46, 0xBD, 0x6B, 0xD5, 0x61, 0x18, 0x35, 0xAE, 0x40, 0xDD, 0x73,
0xF7, 0x89, 0x91, 0x30, 0x5A, 0xEB, 0x3C, 0xEE, 0x85, 0x7C, 0xA2, 0x40,
0x76, 0x3B, 0xA9, 0xC6, 0xB8, 0x47, 0xD8, 0x2A, 0xE7, 0x92, 0x91, 0x6A,
0x73, 0xE9, 0xB1, 0x72, 0x39, 0x9F, 0x29, 0x9F, 0xA2, 0x98, 0xD3, 0x5F,
0x5E, 0x58, 0x86, 0x65, 0x0F, 0xA1, 0x84, 0x65, 0x06, 0xD1, 0xDC, 0x8B,
0xC9, 0xC7, 0x73, 0xC8, 0x8C, 0x6A, 0x2F, 0xE5, 0xC4, 0xAB, 0xD1, 0x1D,
0x8A
};
static
#ifndef CC_BUILD_SYMBIAN
const
#endif
br_x509_trust_anchor TAs[7] = {
{
{ (unsigned char *)TA0_DN, sizeof TA0_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
} }
}
},
{
{ (unsigned char *)TA1_DN, sizeof TA1_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ {
(unsigned char *)TA1_RSA_N, sizeof TA1_RSA_N,
(unsigned char *)TA1_RSA_E, sizeof TA1_RSA_E,
} }
}
},
{
{ (unsigned char *)TA2_DN, sizeof TA2_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ {
(unsigned char *)TA2_RSA_N, sizeof TA2_RSA_N,
(unsigned char *)TA2_RSA_E, sizeof TA2_RSA_E,
} }
}
},
{
{ (unsigned char *)TA3_DN, sizeof TA3_DN },
BR_X509_TA_CA,
{
#if defined CC_BUILD_SYMBIAN
BR_KEYTYPE_EC
/* set in SSL.c */
#else
BR_KEYTYPE_EC,
{ .ec = {
BR_EC_secp384r1,
(unsigned char *)TA3_EC_Q, sizeof TA3_EC_Q,
} }
#endif
}
},
{
{ (unsigned char *)TA4_DN, sizeof TA4_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ {
(unsigned char *)TA4_RSA_N, sizeof TA4_RSA_N,
(unsigned char *)TA4_RSA_E, sizeof TA4_RSA_E,
} }
}
},
{
{ (unsigned char *)TA5_DN, sizeof TA5_DN },
BR_X509_TA_CA,
{
BR_KEYTYPE_RSA,
{ {
(unsigned char *)TA5_RSA_N, sizeof TA5_RSA_N,
(unsigned char *)TA5_RSA_E, sizeof TA5_RSA_E,
} }
}
},
{
{ (unsigned char *)TA6_DN, sizeof TA6_DN },
BR_X509_TA_CA,
{
#if defined CC_BUILD_SYMBIAN
BR_KEYTYPE_EC
/* set in SSL.c */
#else
BR_KEYTYPE_EC,
{ .ec = {
BR_EC_secp384r1,
(unsigned char *)TA6_EC_Q, sizeof TA6_EC_Q,
} }
#endif
}
}
};
#define TAs_NUM 7

BIN
misc/certs/isrg-root-x2.der Normal file

Binary file not shown.

BIN
misc/certs/isrgrootx1.der Normal file

Binary file not shown.

BIN
misc/certs/r4.crt Normal file

Binary file not shown.

96
misc/dreamcast/Makefile Normal file
View File

@@ -0,0 +1,96 @@
ifeq ($(strip $(KOS_BASE)),)
$(warning Please set KOS variables in your environment. For example:)
$(warning source /opt/toolchains/dc/kos/environ.sh)
$(error Failed to find KallistiOS installation)
endif
#---------------------------------------------------------------------------------
# Configurable options
#---------------------------------------------------------------------------------
# Directory where object files are placed
BUILD_DIR := build/dc
# List of directories containing source code
SOURCE_DIRS := src third_party/bearssl/src misc/dreamcast
# Name of the final output
TARGET := ClassiCube-dc
# Additional libraries to link against
LIBS = -lm -lppp -lkosfat
# List of directories containing more header files
INCLUDES = -Ithird_party/bearssl/inc
#---------------------------------------------------------------------------------
# Code generation
#---------------------------------------------------------------------------------
S_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.S))
C_FILES := $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))
OBJS := $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.S=%.o)))
CFLAGS := -g -DNDEBUG -O3 -fipa-pta -fno-pie -flto=auto -fomit-frame-pointer -fbuiltin -ffast-math -ffp-contract=fast -mfsrra -mfsca -pipe -fno-math-errno
LDFLAGS = -g
# Dependency tracking
DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.d
DEPFILES := $(OBJS:%.o=%.d)
#---------------------------------------------------------------------------------
# Main targets
#---------------------------------------------------------------------------------
default: $(BUILD_DIR) $(TARGET).cdi
clean:
rm $(TARGET).cdi $(TARGET).iso $(TARGET).elf $(TARGET)-scr.bin $(TARGET).bin $(OBJS)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
#---------------------------------------------------------------------------------
# Executable generation
#---------------------------------------------------------------------------------
$(TARGET).elf: $(OBJS)
kos-cc $(LDFLAGS) $^ -o $@ $(LIBS)
$(TARGET).bin: $(TARGET).elf
sh-elf-objcopy -R .stack -O binary $(TARGET).elf $(TARGET).bin
# https://dcemulation.org/phpBB/viewtopic.php?t=105269
$(TARGET)-scr.bin: $(TARGET).bin
$(KOS_BASE)/utils/scramble/scramble $(TARGET).bin $(TARGET)-scr.bin
$(TARGET).iso: $(TARGET)-scr.bin
mkdir -p ISO_FILES
cp $(TARGET)-scr.bin ISO_FILES/1ST_READ.BIN
mkdir -p ISO_FILES/audio
mkdir -p ISO_FILES/maps
mkdir -p ISO_FILES/texpacks
mkdir -p ISO_FILES/texturecache
cp misc/dreamcast/classicube.zip ISO_FILES/texpacks/default.zip
cp misc/dreamcast/IP.BIN IP.BIN
mkisofs -G IP.BIN -C 0,11702 -J -l -r -quiet -o $(TARGET).iso ISO_FILES
# genisoimage -V ClassiCube -G IP.BIN -joliet -rock -l -o $(TARGET).iso ISO_FILES
$(TARGET).cdi: $(TARGET).iso
cdi4dc $(TARGET).iso $(TARGET).cdi
#---------------------------------------------------------------------------------
# Object generation
#---------------------------------------------------------------------------------
$(BUILD_DIR)/%.o: src/%.c
kos-cc $(CFLAGS) $(INCLUDES) $(DEPFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o: third_party/bearssl/src/%.c
kos-cc $(CFLAGS) $(INCLUDES) -c $< -o $@
$(BUILD_DIR)/%.o: misc/dreamcast/%.S
kos-cc $(DEPFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
# Dependency tracking
#---------------------------------------------------------------------------------
$(DEPFILES):
include $(wildcard $(DEPFILES))

196
misc/dreamcast/VertexClip.S Normal file
View File

@@ -0,0 +1,196 @@
! r1 = v1, CLOBBERS
! r2 = v2, CLOBBERS
! r3 = OUT, CLOBBERS
! r4 = TMP 1, preserved
! r5 = TMP 2, preserved
! r0 = CL0, CLOBBERS
! FR0 = 0
! FR1 = 0
! FR2 = A.1
! FR3 = B.1
! FR4 = 0
! FR5 = 0
! FR6 = A.2
! FR7 = B.2
! FR8 = 0
! FR9 = 0
! FR10 = invT
! FR11 = t
#define TM1 r0 // CLOBBERED, temp register 1
#define TM2 r4 // PRESERVED, temp register 2
#define CLO r5 // PRESERVED, output colour
#define IN1 r1 // CLOBBERED, input vertex 1
#define IN2 r2 // CLOBBERED, input vertex 2
#define OUT r3 // CLOBBERED, output vertex
#define CL1 r1 // CLOBBERED, input colour 1
#define CL2 r2 // CLOBBERED, input colour 2
! Calculates the near plane intersection point between two points:
! float t = fabsf(v1->z) / fabsf(v2->z - v1->z)
! float invt = 1.0f - t;
!
! out->x = invt * v1->x + t * v2->x;
! out->y = invt * v1->y + t * v2->y;
! out->z = 0.0f; // clipped against near plane anyways (I.e Z/W = 0 --> Z = 0)
!
! out->u = invt * v1->u + t * v2->u;
! out->v = invt * v1->v + t * v2->v;
! out->w = invt * v1->w + t * v2->w;
!
! out->b = invt * v1->b + t * v2->b;
! out->g = invt * v1->g + t * v2->g;
! out->r = invt * v1->r + t * v2->r;
! out->a = invt * v1->a + t * v2->a;
! To optimise these calculations, FIPR is used:
! FIPR = FVm.x*FVn.x + FVm.y*FVn.x + FVm.z*FVn.z + FVm.w*FVn.w --> FVn.w
! FIPR can be used to accomplish "vout->Q = invt * v1->Q + t * v2->Q" by:
! - assigning x/y components to 0 for both vectors
! - assigning t and invT to z/w of FVm vector
! - assigning v1 and v2 to z/w of FVn vector
! FIPR = 0*0 + 0*0 + t*v1->Q + invT*v2->Q --> FVn.w
! FIPR = t*v1->Q + invT*v2->Q --> FVn.w
.global _ClipLine
.align 4
_ClipLine:
mov.l r4,@-r15 ! LS, push(r4)
mov.l r5,@-r15 ! LS, push(r5)
mov IN1, TM1 ! MT, tmp = &v1
fldi0 fr4 ! LS, fr4 = 0
add #12, TM1 ! EX, tmp = &v1->z
fmov.s @TM1, fr2 ! LS, fr2 = v1->z
mov IN2, TM1 ! MT, tmp = &v2
fldi0 fr5 ! LS, fr5 = 0
add #12, TM1 ! EX, tmp = &v2->z
fmov.s @TM1,fr11 ! LS, fr11 = v2->z
fsub fr2,fr11 ! FE, fr11 = v2->z - v1->z
fldi0 fr8 ! LS, fr8 = 0
fmul fr11,fr11 ! FE, fr11 = (v2->z - v1->z) * (v2->z * v1->z)
fldi0 fr9 ! LS, fr9 = 0
fldi0 fr0 ! LS, fr0 = 0
fldi0 fr1 ! LS, fr1 = 0
fsrra fr11 ! FE, fr11 = 1 / abs(v2->z - v1->z)
fabs fr2 ! LS, fr2 = abs(v1->z)
fmul fr2,fr11 ! FE, fr11 = abs(v1->Z) / abs(v2->z - v1->z) --> t
add #4, IN1 ! EX, v1 += 4
fldi1 fr10 ! LS, fr10 = 1
add #4, IN2 ! EX, v2 += 4
add #4, OUT ! EX, OUT += 4
fsub fr11,fr10 ! FE, fr10 = 1.0 - t --> invT
fmov.s @IN1+, fr2 ! LS, A1 = v1->x, v1 += 4
fmov.s @IN2+, fr3 ! LS, B1 = v2->x, v2 += 4
fipr fv8, fv0 ! FE, LERP(A1, B1)
fmov.s @IN1+, fr6 ! LS, A2 = v1->y, v1 += 4
fmov.s @IN2+, fr7 ! LS, B2 = v2->y, v2 += 4
fmov.s fr3,@OUT ! LS, OUT->x = LERP
add #4, OUT ! EX, OUT += 4
fipr fv8, fv4 ! FE, LERP(A2, B2)
add #4, IN1 ! EX, v1 += 4
add #4, IN2 ! EX, v2 += 4
fmov.s fr7,@OUT ! LS, OUT->y = LERP
add #4, OUT ! EX, OUT += 4
fmov.s fr1,@OUT ! LS, OUT->z = 0
add #4, OUT ! EX, OUT += 4
fmov.s @IN1+, fr2 ! LS, A1 = v1->u, v1 += 4
fmov.s @IN2+, fr3 ! LS, B1 = v2->u, v2 += 4
fipr fv8, fv0 ! FE, LERP(A1, B1)
fmov.s @IN1+, fr6 ! LS, A2 = v1->v, v1 += 4
fmov.s @IN2+, fr7 ! LS, B2 = v2->v, v2 += 4
fmov.s fr3,@OUT ! LS, OUT->u = LERP
add #4, OUT ! EX, OUT += 4
fipr fv8, fv4 ! FE, LERP(A2, B2)
add #4, IN1 ! EX, v1 += 4
add #4, IN2 ! EX, v2 += 4
fmov.s @IN1,fr2 ! LS, A1 = v1->w
fmov.s @IN2,fr3 ! LS, B1 = v2->w
fmov.s fr7,@OUT ! LS, OUT->v = LERP
add #8, OUT ! EX, OUT += 8
fipr fv8, fv0 ! FE, LERP(A1, B1)
add #-4, IN1 ! EX, v1 -= 4
add #-4, IN2 ! EX, v2 -= 4
fmov.s fr3,@OUT ! LS, OUT->w = lerp
add #-4, OUT ! EX, OUT -= 4
mov.l @IN1,CL1 ! LS, ACOLOR = v1->bgra
mov.l @IN2,CL2 ! LS, BCOLOR = v2->bgra
! Bypass interpolation if unnecessary
cmp/eq CL1,CL2 ! MT, T = ACOLOR == BCOLOR
bt.s 1f ! BR, if (T) goto 1;
mov CL1,CLO ! MT, OUTCOLOR = ACOLOR (branch delay instruction)
! Interpolate B
extu.b CL1,TM1 ! EX, val = ACOLOR.b
lds TM1,fpul ! CO, FPUL = val
float fpul,fr2 ! EX, fr2 = float(FPUL)
extu.b CL2,TM1 ! EX, val = BCOLOR.b
lds TM1,fpul ! CO, FPUL = val
float fpul,fr3 ! EX, fr3 = float(FPUL)
fipr fv8, fv0 ! FE, LERP(A1, B1)
shlr8 CL1 ! EX, ACOLOR >>= 8
ftrc fr3,fpul ! FE, FPUL = int(lerp)
shlr8 CL2 ! EX, BCOLOR >>= 8
sts fpul,TM2 ! CO, tmp = FPUL
! Interpolate G
extu.b CL1,TM1 ! EX, val = ACOLOR.g
lds TM1,fpul ! CO, FPUL = val
float fpul,fr2 ! EX, fr2 = float(FPUL)
extu.b CL2,TM1 ! EX, val = BCOLOR.g
lds TM1,fpul ! CO, FPUL = val
float fpul,fr3 ! EX, fr3 = float(FPUL)
fipr fv8, fv0 ! FE, LERP(A1, B1)
shlr8 CL1 ! EX, ACOLOR >>= 8
ftrc fr3,fpul ! FE, FPUL = int(lerp)
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
mov TM2,CLO ! MT, OUTCOLOR.b = tmp
shlr8 CL2 ! EX, BCOLOR >>= 8
sts fpul,TM2 ! CO, tmp = FPUL
! Interpolate R
extu.b CL1,TM1 ! EX, val = ACOLOR.r
lds TM1,fpul ! CO, FPUL = val
float fpul,fr2 ! EX, fr2 = float(FPUL)
extu.b CL2,TM1 ! EX, val = BCOLOR.r
lds TM1,fpul ! CO, FPUL = val
float fpul,fr3 ! EX, fr3 = float(FPUL)
fipr fv8, fv0 ! FE, LERP(A1, B1)
shlr8 CL1 ! EX, ACOLOR >>= 8
ftrc fr3,fpul ! FE, FPUL = int(lerp)
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
shll8 TM2 ! EX, tmp <<= 8
or TM2,CLO ! EX, OUTCOLOR.g |= tmp
shlr8 CL2 ! EX, BCOLOR >>= 8
sts fpul,TM2 ! CO, tmp = FPUL
! Interpolate A
extu.b CL1,TM1 ! EX, val = ACOLOR.a
lds TM1,fpul ! CO, FPUL = val
float fpul,fr2 ! EX, fr2 = float(FPUL)
extu.b CL2,TM1 ! EX, val = BCOLOR.a
lds TM1,fpul ! CO, FPUL = val
float fpul,fr3 ! EX, fr3 = float(FPUL)
fipr fv8, fv0 ! FE, LERP(A1, B1)
ftrc fr3,fpul ! FE, FPUL = int(lerp)
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
shll16 TM2 ! EX, tmp <<= 16
or TM2,CLO ! EX, OUTCOLOR.r |= tmp
sts fpul,TM2 ! CO, tmp = FPUL
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
shll16 TM2 ! EX, tmp <<= 16
shll8 TM2 ! EX, tmp <<= 8
or TM2,CLO ! EX, OUTCOLOR.a |= tmp
1:
mov.l CLO,@OUT ! LS, OUT->color = OUTCOLOR
mov.l @r15+,r5 ! LS, pop(r5)
rts ! CO, return after executing instruction in delay slot
mov.l @r15+,r4 ! LS, pop(r4)
.size _ClipLine, .-_ClipLine
.type _ClipLine,%function

View File

@@ -0,0 +1,210 @@
! Calculates vertex as the near plane intersection point between two points:
! float t = fabsf(v1->z) / fabsf(v2->z - v1->z)
! float w = (1 - t) * v1->w + t * v2->w;
!
! out->c = type << 24
! out->x = ((1 - t) * v1->x + t * v2->x) * 1/w
! out->y = ((1 - t) * v1->y + t * v2->y) * 1/w
! out->w = 1/w
!
! out->u = (1 - t) * v1->u + t * v2->u;
! out->v = (1 - t) * v1->v + t * v2->v;
!
! out->b = (1 - t) * v1->b + t * v2->b;
! out->g = (1 - t) * v1->g + t * v2->g;
! out->r = (1 - t) * v1->r + t * v2->r;
! out->a = (1 - t) * v1->a + t * v2->a;
! Optimisations:
! - w always ends up being zNear
! - Calculations of (1 - t) * v1 + t * v2 can be rearranged to t * (v2 - v1) + v1
! - These rearranges calculations can then take advantage of FMAC
! Final calculation:
! out->c = type << 24
! out->x = ((v2->x - v1->x) + v1->x) * 1/zNear
! out->y = ((v2->y - v1->y) + v1->y) * 1/zNear
! out->w = 1/zNear
!
! out->u = (v2->u - v1->u) + v1->u;
! out->v = (v2->v - v1->v) + v1->v;
!
! out->b = (v2->b - v1->b) + v1->b;
! out->g = (v2->g - v1->g) + v1->g;
! out->r = (v2->r - v1->r) + v1->r;
! out->a = (v2->a - v1->a) + v1->a;
! INPUT ARGUMENTS
#define IN1 r4 // input vertex 1
#define IN2 r5 // input vertex 2
#define OUT r6 // output vertex
#define TYP r7 // type/flags for output vertex
#define TM1 r1 // temp register 1
#define TM2 r3 // temp register 2
#define CL1 r4 // input colour 1
#define CL2 r5 // input colour 2
#define CLO r7 // output colour
#define F_T fr0
#define F_W fr1
#define F_X1 fr2
#define F_X2 fr3
#define F_Y1 fr4
#define F_Y2 fr5
#define F_U1 fr6
#define F_U2 fr7
#define F_V1 fr8
#define F_V2 fr9
#define F_Z1 fr10
#define F_Z2 fr11
#define Ftmp fr11
.global _ClipEdge
.align 4
_ClipEdge:
fschg ! FE (swap to 32 bit FPU loads/stores)
! Start calculating interpolation factor
add #28, IN1 ! EX, IN1 = &v1->z
mov.l _NEAR_CLIP_W,TM1 ! LS, tmp = invW (1/zNear)
fmov.s @IN1, F_Z1 ! LS, Z1 = v1->z
add #28, IN2 ! EX, IN = &v2->z
fmov.s @IN2, F_Z2 ! LS, Z2 = v2->z
shll16 TYP ! EX, TYP <<= 16
fsub F_Z1, Ftmp ! FE, tmp = v2->z - v1->z
! Load W
lds TM1,fpul ! LS, FPUL = invW (1/zNear)
add #-24, IN1 ! EX, IN1 = &v1->x
fsts fpul,F_W ! LS, invW = FPUL
add #-24, IN2 ! EX, IN2 = &v2->x
! Finish calculating interpolation factor
shll8 TYP ! EX, TYP <<= 8
fmul Ftmp,Ftmp ! FE, tmp = (v2->z - v1->z) * (v2->z * v1->z)
mov.l TYP,@OUT ! LS, dst->cmd = TYPE
! Load components
fmov.s @IN1+, F_X1 ! LS, X1 = v1->x
fmov.s @IN2+, F_X2 ! LS, X2 = v2->x
fmov.s @IN1+, F_Y1 ! LS, Y1 = y1->x
fmov.s @IN2+, F_Y2 ! LS, Y2 = y2->x
fsrra Ftmp ! FE, tmp = 1 / abs(v2->z - v1->z)
add #4, IN1 ! EX, skip over W
fabs F_Z1 ! LS, z1 = abs(v1->z)
add #4, IN2 ! EX, skip over W
fmov.s @IN1+, F_U1 ! LS, U1 = v1->u
fmov.s @IN2+, F_U2 ! LS, U2 = v2->u
fmov.s @IN1+, F_V1 ! LS, V1 = v1->v
fmul F_Z1,Ftmp ! FE, tmp = abs(v1->Z) / abs(v2->z - v1->z)
fmov.s @IN2+, F_V2 ! LS, V2 = v2->v
! Interpolate vertices
fsub F_X1, F_X2 ! FE, X2 = X2 - X1
fsub F_Y1, F_Y2 ! FE, Y2 = Y2 - Y1
fsub F_U1, F_U2 ! FE, U2 = U2 - U1
fmov Ftmp, F_T ! LS, T = tmp
fsub F_V1, F_V2 ! FE, V2 = V2 - V1
fmac F_T,F_X2,F_X1 ! FE, X = T * (X2 - X1) + X1
fmac F_T,F_Y2,F_Y1 ! FE, Y = T * (Y2 - Y1) + Y1
fmac F_T,F_U2,F_U1 ! FE, U = T * (U2 - U1) + U1
fmac F_T,F_V2,F_V1 ! FE, V = T * (V2 - V1) + V1
! Adjust by w
fmul F_W, F_X1 ! FE, x = invW * x
fmul F_W, F_Y1 ! FE, x = invY * x
! Load colours and check if equal
mov.l @IN1,CL1 ! LS, ACOLOR = v1->bgra
mov.l @IN2,CL2 ! LS, BCOLOR = v2->bgra
cmp/eq CL1,CL2 ! MT, T = ACOLOR == BCOLOR
add #28, OUT ! EX, dst = &dst->padding
! Bypass RGBA interpolation if unnecessary
bt.s 1f ! BR, if (T) goto 1;
mov CL1,CLO ! MT, OUTCOLOR = ACOLOR (branch delay instruction)
! Interpolate B
extu.b CL1,TM1 ! EX, val = ACOLOR.b
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z1 ! FE, C1 = float(val)
extu.b CL2,TM1 ! EX, val = BCOLOR.b
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z2 ! FE, C2 = float(val)
fsub F_Z1, F_Z2 ! FE, C2 = C2 - C1
fmac F_T,F_Z2,F_Z1 ! FE, C = T * (C2 - C1) + C1
shlr8 CL1 ! EX, ACOLOR >>= 8
shlr8 CL2 ! EX, BCOLOR >>= 8
ftrc F_Z1,fpul ! FE, FPUL = int(C)
sts fpul,TM2 ! LS, tmp = FPUL
! Interpolate G
extu.b CL1,TM1 ! EX, val = ACOLOR.g
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z1 ! FE, C1 = float(val)
extu.b CL2,TM1 ! EX, val = BCOLOR.g
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z2 ! FE, C2 = float(val)
fsub F_Z1, F_Z2 ! FE, C2 = C2 - C1
fmac F_T,F_Z2,F_Z1 ! FE, C = T * (C2 - C1) + C1
shlr8 CL1 ! EX, ACOLOR >>= 8
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
mov TM2,CLO ! MT, OUTCOLOR.b = tmp
shlr8 CL2 ! EX, BCOLOR >>= 8
ftrc F_Z1,fpul ! FE, FPUL = int(C)
sts fpul,TM2 ! LS, tmp = FPUL
! Interpolate R
extu.b CL1,TM1 ! EX, val = ACOLOR.r
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z1 ! FE, C1 = float(val)
extu.b CL2,TM1 ! EX, val = BCOLOR.r
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z2 ! FE, C2 = float(val)
fsub F_Z1, F_Z2 ! FE, C2 = C2 - C1
fmac F_T,F_Z2,F_Z1 ! FE, C = T * (C2 - C1) + C1
shlr8 CL1 ! EX, ACOLOR >>= 8
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
shll8 TM2 ! EX, tmp <<= 8
or TM2,CLO ! EX, OUTCOLOR.g |= tmp
shlr8 CL2 ! EX, BCOLOR >>= 8
ftrc F_Z1,fpul ! FE, FPUL = int(C)
sts fpul,TM2 ! LS, tmp = FPUL
! Interpolate A
extu.b CL1,TM1 ! EX, val = ACOLOR.a
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z1 ! FE, C1 = float(val)
extu.b CL2,TM1 ! EX, val = BCOLOR.a
lds TM1,fpul ! LS, FPUL = val
float fpul,F_Z2 ! FE, C2 = float(val)
fsub F_Z1, F_Z2 ! FE, C2 = C2 - C1
fmac F_T,F_Z2,F_Z1 ! FE, C = T * (C2 - C1) + C1
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
shll16 TM2 ! EX, tmp <<= 16
or TM2,CLO ! EX, OUTCOLOR.r |= tmp
ftrc F_Z1,fpul ! FE, FPUL = int(C)
sts fpul,TM2 ! LS, tmp = FPUL
extu.b TM2,TM2 ! EX, tmp = (uint8)tmp
shll16 TM2 ! EX, tmp <<= 16
shll8 TM2 ! EX, tmp <<= 8
or TM2,CLO ! EX, OUTCOLOR.a |= tmp
1:
! Store output
mov.l CLO,@-OUT ! LS, dst->color = OUTCOLOR
fmov.s F_V1,@-OUT ! LS, dst->v = v
fmov.s F_U1,@-OUT ! LS, dst->u = u
fmov.s F_W ,@-OUT ! LS, dst->w = invW
fmov.s F_Y1,@-OUT ! LS, dst->y = y
fmov.s F_X1,@-OUT ! LS, dst->x = x
fschg ! FE (swap to 64 bit FPU loads/stores)
rts ! CO, return after executing instruction in delay slot
pref @OUT ! LS, trigger store queue flush
.size _ClipEdge, .-_ClipEdge
.type _ClipEdge, %function
.align 4
_NEAR_CLIP_W:
.float 0
.global _NEAR_CLIP_W

611
misc/dreamcast/VertexDraw.S Normal file
View File

@@ -0,0 +1,611 @@
! r8 = STORE_QUEUE
! r9 = num vertices left
! r10 = PVR_CMD_VERTEX
! r11 = PVR_CMD_VERTEX_EOL
! r12 = ClipLine function
! r13 = cur vertex
! r14 = next vertex (prefetch)
#define R_VTX r10
#define R_EOL r11
#define REG_CMD_VTX r10
#define REG_CMD_EOL r11
#define REG_CLIPFUNC r12
.align 4
! Pushes a vertex to the store queue
! CLOBBERS: r2
! INPUTS: R (vertex), r8 (SQ global)
! OUTPUTS: r8 altered
.macro PushVertex R
! memcpy(r8, \R, 32)
mov.l @(0,\R), r2
mov.l r2, @(0,r8)
mov.l @(4,\R), r2
mov.l r2, @(4,r8)
mov.l @(8,\R), r2
mov.l r2, @(8,r8)
mov.l @(12,\R),r2
mov.l r2,@(12,r8)
mov.l @(16,\R),r2
mov.l r2,@(16,r8)
mov.l @(20,\R),r2
mov.l r2,@(20,r8)
mov.l @(24,\R),r2
mov.l r2,@(24,r8)
mov.l @(28,\R),r2
mov.l r2,@(28,r8)
pref @r8 ! LS, Trigger SQ
add #32,r8 ! EX, SQ += 32
.endm
! Transforms then pushes a vertex to the store queue
! note: Vertices are assumed as pre viewport transformed already
! CLOBBERS: r2, fr0, fr4, fr5
! INPUTS: R (vertex), r8 (SQ global)
! OUTPUTS: R, r8 altered
.macro TransformVertex R
! INVERSE W CALCULATION
add #28, \R ! EX, SRC += 28
fmov.s @\R,fr0 ! LS, fr0 = v->w
fmul fr0,fr0 ! FE, fr0 = fr0 * fr0
add #-28, \R ! EX, SRC -= 28
mov.l @\R+, r2 ! LS, tmp = SRC->flags, SRC += 4
mov.l r2,@r8 ! LS, DST->flags = tmp
fsrra fr0 ! FE, invW = 1 / sqrt(SRC->W * SRC->W)
add #4, r8 ! EX, DST += 4
! COPY U,V
mov.l @(12,\R),r2 ! LS, tmp = SRC->u
mov.l r2,@(12,r8) ! LS, DST->u = tmp
mov.l @(16,\R),r2 ! LS, tmp = SRC->v
mov.l r2,@(16,r8) ! LS, DST->v = tmp
! TRANSFORM X
fmov.s @\R,fr4 ! LS, fr4 = SRC->x
fmul fr0,fr4 ! FE, fr4 = invW * SRC->x
mov.l @(20,\R),r2 ! LS, tmp = SRC->bgra
mov.l r2,@(20,r8) ! LS, SRC->bgra = tmp
add #4, \R ! EX, SRC += 4
fmov.s fr4,@r8 ! LS, DST->x = fr4
! TRANSFORM Y
fmov.s @\R,fr4 ! LS, fr4 = SRC->y
add #8, r8 ! EX, DST += 8
fmul fr0,fr4 ! FE, fr4 = invW * SRC->y
fmov.s fr0,@r8 ! LS, DST->z = invW
add #-4, r8 ! EX, DST -= 4
add #-8, \R ! EX, src -= 8 (back to start of vertex)
fmov.s fr4,@r8 ! LS, DST->y = fr4
add #-8,r8 ! EX, DST -= 8 (back to start of vertex)
pref @r8 ! LS, Trigger SQ
add #32,r8 ! EX, SQ += 32
.endm
#define REG_CLIP1 r1
#define REG_CLIP2 r2
#define REG_V0 r4
#define REG_V1 r5
#define REG_V2 r6
#define REG_V3 r7
! r3 also matches out parameter for ClipLine
#define REG_TMP r3
#define TMP_SET_A \
mov r15, REG_TMP
#define TMP_SET_B \
mov r15, REG_TMP; add #32, REG_TMP
_Case_0_0_0_1:
! v0
! / |
! / |
! .....A....B...
! / |
! v3--v2---v1
sts pr,r13
TMP_SET_A
mov REG_V3, REG_CLIP1
mov REG_V0, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
TMP_SET_B
mov REG_V0, REG_CLIP1
mov REG_V1, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TransformVertex REG_V0
TMP_SET_B
TransformVertex REG_TMP
TMP_SET_A
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_0_0_1_0:
! v1
! / |
! / |
! ....A.....B...
! / |
! v0--v3---v2
sts pr,r13
TMP_SET_A
mov REG_V0, REG_CLIP1
mov REG_V1, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V1, REG_CLIP1
mov REG_V2, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
TMP_SET_A
TransformVertex REG_TMP
TransformVertex REG_V1
TMP_SET_B
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_0_1_0_0:
! v2
! / |
! / |
! ....A.....B...
! / |
! v1--v0---v3
sts pr,r13
TMP_SET_A
mov REG_V1, REG_CLIP1
mov REG_V2, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V2, REG_CLIP1
mov REG_V3, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
TMP_SET_A
TransformVertex REG_TMP
TransformVertex REG_V2
TMP_SET_B
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_1_0_0_0:
! v3
! / |
! / |
! ....A.....B...
! / |
! v2--v1---v0
sts pr,r13
TMP_SET_A
mov REG_V2, REG_CLIP1
mov REG_V3, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V3, REG_CLIP1
mov REG_V0, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
TransformVertex REG_TMP
TMP_SET_A
TransformVertex REG_TMP
TransformVertex REG_V3
lds r13,pr
rts
nop
_Case_0_0_1_1:
! v0-----------v1
! \ |
! ....B..........A...
! \ |
! v3-----v2
sts pr,r13
TMP_SET_A
mov REG_V1, REG_CLIP1
mov REG_V2, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V3, REG_CLIP1
mov REG_V0, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
TransformVertex REG_V1
TMP_SET_A
TransformVertex REG_TMP
TransformVertex REG_V0
TMP_SET_B
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_1_0_0_1:
! v3-----------v0
! \ |
! ....B..........A...
! \ |
! v2-----v1
sts pr,r13
TMP_SET_A
mov REG_V0, REG_CLIP1
mov REG_V1, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V2, REG_CLIP1
mov REG_V3, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_A
TransformVertex REG_TMP
TMP_SET_B
TransformVertex REG_TMP
TransformVertex REG_V0
TransformVertex REG_V3
lds r13,pr
rts
nop
_Case_0_1_1_0:
! v1-----------v2
! \ |
! ....B..........A...
! \ |
! v0-----v3
sts pr,r13
TMP_SET_A
mov REG_V2, REG_CLIP1
mov REG_V3, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
TMP_SET_B
mov REG_V0, REG_CLIP1
mov REG_V1, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TransformVertex REG_V1
TransformVertex REG_V2
TMP_SET_B
TransformVertex REG_TMP
TMP_SET_A
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_1_1_0_0:
! v2-----------v3
! \ |
! ....B..........A...
! \ |
! v1-----v0
sts pr,r13
TMP_SET_A
mov REG_V3, REG_CLIP1
mov REG_V0, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V1, REG_CLIP1
mov REG_V2, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
TransformVertex REG_TMP
TransformVertex REG_V2
TMP_SET_A
TransformVertex REG_TMP
TransformVertex REG_V3
lds r13,pr
rts
nop
_Case_0_1_1_1:
! --v1--
! v0-- --v2
! \ |
! .....B.....A...
! \ |
! v3
! v1,v2,v0 v2,v0,A v0,A,B
sts pr,r13
TMP_SET_A
mov REG_V2, REG_CLIP1
mov REG_V3, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V3, REG_CLIP1
mov REG_V0, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
TransformVertex REG_V1
TransformVertex REG_V2
TransformVertex REG_V0
TMP_SET_A
TransformVertex REG_TMP
TMP_SET_B
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_1_0_1_1:
! --v0--
! v3-- --v1
! \ |
! .....B.....A...
! \ |
! v2
! v0,v1,v3 v1,v3,A v3,A,B
sts pr,r13
TMP_SET_A
mov REG_V1, REG_CLIP1
mov REG_V2, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V2, REG_CLIP1
mov REG_V3, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
mov.l REG_CMD_VTX, @REG_V3
TransformVertex REG_V0
TransformVertex REG_V1
TransformVertex REG_V3
TMP_SET_A
TransformVertex REG_TMP
TMP_SET_B
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_1_1_0_1:
! --v3--
! v2-- --v0
! \ |
! .....B.....A...
! \ |
! v1
! v3,v0,v2 v0,v2,A v2,A,B
sts pr,r13
TMP_SET_A
mov REG_V0, REG_CLIP1
mov REG_V1, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V1, REG_CLIP1
mov REG_V2, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
mov.l REG_CMD_VTX, @REG_V3
TransformVertex REG_V3
TransformVertex REG_V0
TransformVertex REG_V2
TMP_SET_A
TransformVertex REG_TMP
TMP_SET_B
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_1_1_1_0:
! --v2--
! v1-- --v3
! \ |
! .....B.....A...
! \ |
! v0
! v2,v3,v1 v3,v1,A v1,A,B
sts pr,r13
TMP_SET_A
mov REG_V3, REG_CLIP1
mov REG_V0, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_VTX, @REG_TMP
TMP_SET_B
mov REG_V0, REG_CLIP1
mov REG_V1, REG_CLIP2
jsr @REG_CLIPFUNC
mov.l REG_CMD_EOL, @REG_TMP
mov.l REG_CMD_VTX, @REG_V3
TransformVertex REG_V2
TransformVertex REG_V3
TransformVertex REG_V1
TMP_SET_A
TransformVertex REG_TMP
TMP_SET_B
TransformVertex REG_TMP
lds r13,pr
rts
nop
_Case_1_1_1_1:
! Triangle strip: {1,2,0} {2,0,3}
TransformVertex REG_V1
TransformVertex REG_V2
TransformVertex REG_V0
TransformVertex REG_V3
rts
nop
.global _ProcessVertexList
.align 4
_ProcessVertexList:
! STORE CPU REGISTERS
mov.l r8,@-r15
mov.l r9,@-r15
mov.l r10,@-r15
mov.l r11,@-r15
mov.l r12,@-r15
mov.l r13,@-r15
mov.l r14,@-r15
sts.l pr,@-r15
! REGISTER SETUP
mov r4,r14
mov r4,r13
mov.l .CLIPFUNC,r12
mov.l .PVR_EOL, r11
mov.l .PVR_VTX, r10
mov r5,r9
mov r6,r8
bra SUBMIT_LOOP
add #-64,r15
! Submits a PVR2 TA GPU command
DO_CMD:
PushVertex REG_V0
bra NEXT_ITER
nop
SUBMIT_LOOP:
mov.l @r13,r0 ! FLAGS = CUR->flags
add #32,r14 ! NEXT += sizeof(Vertex)
mov r0,r2 ! TYPE = FLAGS
and r11,r2 ! TYPE = FLAGS & 0xF000000 (reuse PVR_CMD_VERTEX_EOL as type mask)
! Check for PVR_CMD_VERTEX
cmp/eq r10,r2 ! T = r2 == PVR_CMD_VERTEX
bt.s NEXT_ITER ! if (T) goto NEXT_ITER
pref @r14 ! prefetch(NEXT) -- always executed
! Check for non PVR_CMD_VERTEX_EOL
cmp/eq r11,r2 ! T = r2 == PVR_CMD_VERTEX_EOL
bf.s DO_CMD ! if (!T) goto DO_CMD
! PVR_CMD_VERTEX_EOL case
extu.b r0,r1 ! EX, MASK = FLAGS & 0xFF (branch delay slot)
! Prepare and then jump to quad drawing function, based on quad clipflags
mova .CASES,r0 ! LS, r0 = CASES
mov r13,r7 ! MT, r7 = v3
shll2 r1 ! EX, MASK <<= 2
mov r13,r6 ! MT, r6 = v3
mov.l @(r0,r1),r2 ! LS, r1 = CASES[MASK]
mov r13,r5 ! MT, r5 = v3
add #-32,r6 ! EX, r6 = v3 - 1 (v2)
mov r13,r4 ! MT, r4 = v3
add #-64,r5 ! EX, r5 = v3 - 2 (v1)
jsr @r2 ! C0, jump CASES[MASK]
add #-96,r4 ! EX, r4 = v3 - 3 (v0) (branch delay slot)
NEXT_ITER:
dt r9 ! NUM--; T = NUM == 0
bf.s SUBMIT_LOOP
mov r14,r13 ! CUR = NEXT
add #64,r15
! RESTORE CPU REGISTERS
lds.l @r15+,pr
mov.l @r15+,r14
mov.l @r15+,r13
mov.l @r15+,r12
mov.l @r15+,r11
mov.l @r15+,r10
mov.l @r15+,r9
rts
mov.l @r15+,r8
.size _ProcessVertexList, .-_ProcessVertexList
.type _ProcessVertexList, %function
.align 4
.VP_1:
.long _vp
.PVR_VTX:
.long 0xE0000000
.PVR_EOL:
.long 0xF0000000
.CLIPFUNC:
.long _ClipLine
BUGGY_CASE:
rts
nop
! CASES table holds the functions to transfer a quad,
! based on the visibility clipflags of the 4 vertices
! e.g. CASES[15] = V0_VIS | V1_VIS | V2_VIS | V3_VIS (all 4 visible)
.CASES:
.long BUGGY_CASE ! Should never happen
.long _Case_0_0_0_1
.long _Case_0_0_1_0
.long _Case_0_0_1_1
.long _Case_0_1_0_0
.long BUGGY_CASE ! V0_VIS | V2_VIS, Should never happen
.long _Case_0_1_1_0
.long _Case_0_1_1_1
.long _Case_1_0_0_0
.long _Case_1_0_0_1
.long BUGGY_CASE ! V1_VIS | V3_VIS, Should never happen
.long _Case_1_0_1_1
.long _Case_1_1_0_0
.long _Case_1_1_0_1
.long _Case_1_1_1_0
.long _Case_1_1_1_1

View File

@@ -0,0 +1,230 @@
#define FLG r0 // clip flags
#define TMP r1 // temp
#define VTX r2 // PVR_CMD_VERTEX
#define EOS r3 // PVR_CMD_VERTEX_EOL
#define SRC r4 // src pointer ARG
#define DST r5 // dst pointer ARG
#define CNT r6 // quads count ARG
#define PFT r7 // prefetch address
#define ZERO fr0 // 0.0
#define F_U fr1 // vertex.u
#define F_V fr2 // vertex.v
#define F_C fr3 // vertex.colour
#define F_X fr4 // vertex.x
#define F_Y fr5 // vertex.y
#define F_Z fr6 // vertex.z
#define F_W fr7 // vertex.w
#define XYZW fv4 // vertex.xyzw
! =========================================================
! ========================= TRANSFORM SETUP ===============
! =========================================================
.macro TransformSetup
mov SRC, PFT ! MT, pft = src
add #-32, DST ! EX, dst -= sizeof(VERTEX)
mov #0xE0, VTX ! EX, VTX = 0x00 00 00 E0
pref @PFT ! LS, PREFETCH pft (first vertex)
shll16 VTX ! EX, VTX = 0x00 E0 00 00
shll8 VTX ! EX, VTX = 0xE0 00 00 00 (PVR_CMD_VERTEX)
mov #0xF0, EOS ! EX, EOS = 0x00 00 00 F0
shll16 EOS ! EX, EOS = 0x00 F0 00 00
shll8 EOS ! EX, EOS = 0xF0 00 00 00 (PVR_CMD_VERTEX_EOL)
fldi0 ZERO ! LS, fr0 = 0.0
.endm
.macro TransformEnd
add #32, DST ! EX, DST += sizeof(VERTEX)
rts ! CO, return after executing instruction in delay slot
mov DST, r0 ! MT, r0 = DST
.endm
! =========================================================
! ========================= VERTEX LOADING ================
! =========================================================
.macro LoadColouredVertex
! LOAD XYZ
fmov @SRC+, F_X ! LS, X = src->x
fmov @SRC+, F_Y ! LS, Y = src->y
fmov @SRC+, F_Z ! LS, Z = src->z
fldi1 F_W ! LS, W = 1.0
! PREPARE NEXT VERTEX
add #16, PFT ! EX, pft += VERTEX_STRIDE
pref @PFT ! LS, PREFETCH pft (next vertex)
add #64, DST ! EX, dst += 2 * sizeof(VERTEX)
! TRANSFORM VERTEX
ftrv xmtrx, XYZW ! FE, TRANSFORM(XYZW)
! LOAD ATTRIBUTES
fmov @SRC+, F_C ! LS, C = src->color
.endm
.macro LoadTexturedVertex
! LOAD XYZ
fmov @SRC+, F_X ! LS, X = src->x
fmov @SRC+, F_Y ! LS, Y = src->y
fmov @SRC+, F_Z ! LS, Z = src->z
fldi1 F_W ! LS, W = 1.0
! PREPARE NEXT VERTEX
add #24, PFT ! EX, pft += VERTEX_STRIDE
pref @PFT ! LS, PREFETCH pft (next vertex)
add #64, DST ! EX, dst += 2 * sizeof(VERTEX)
! TRANSFORM VERTEX
ftrv xmtrx, XYZW ! FE, TRANSFORM(XYZW)
! LOAD ATTRIBUTES
fmov @SRC+, F_C ! LS, C = src->color
fmov @SRC+, F_U ! LS, U = src->u
fmov @SRC+, F_V ! LS, V = src->v
.endm
! =========================================================
! ========================= VERTEX OUTPUT =================
! =========================================================
! To take advantage of SH4 dual instruction processing,
! clipflag calculation and vertex output are interleaved
.macro ProcessVertex1
fmov.s F_Z,@-DST ! LS, dst->z = Z
fmov.s F_C,@-DST ! LS, dst->c = C
fmov.s F_V,@-DST ! LS, dst->v = V
fcmp/gt ZERO, F_Z ! FE, T = Z > 0
fmov.s F_U,@-DST ! LS, dst->u = U
movt FLG ! EX, CLIPFLAGS = T
fmov.s F_W,@-DST ! LS, dst->w = W
fmov.s F_Y,@-DST ! LS, dst->y = Y
fmov.s F_X,@-DST ! LS, dst->x = X
mov.l VTX,@-DST ! LS, dst->flags = PVR_CMD_VERTEX
.endm
.macro ProcessVertex2
fmov.s F_Z,@-DST ! LS, dst->z = Z
fmov.s F_C,@-DST ! LS, dst->c = C
fmov.s F_V,@-DST ! LS, dst->v = V
fcmp/gt ZERO,F_Z ! FE, T = Z > 0
fmov.s F_U,@-DST ! LS, dst->u = U
movt TMP ! EX, tmp = T
fmov.s F_W,@-DST ! LS, dst->w = W
add TMP,TMP ! EX, tmp = tmp + tmp
fmov.s F_Y,@-DST ! LS, dst->y = Y
or TMP,FLG ! EX, CLIPFLAGS |= tmp (T << 1)
fmov.s F_X,@-DST ! LS, dst->x = X
mov.l VTX,@-DST ! LS, dst->flags = PVR_CMD_VERTEX
.endm
.macro ProcessVertex3
fmov.s F_Z,@-DST ! LS, dst->z = Z
fmov.s F_C,@-DST ! LS, dst->c = C
fmov.s F_V,@-DST ! LS, dst->v = V
fcmp/gt ZERO, F_Z ! FE, T = Z > 0
fmov.s F_U,@-DST ! LS, dst->u = U
movt TMP ! EX, tmp = T
fmov.s F_W,@-DST ! LS, dst->w = W
fmov.s F_Y,@-DST ! LS, dst->y = Y
shll2 TMP ! EX, tmp = tmp << 2
fmov.s F_X,@-DST ! LS, dst->x = X
or TMP,FLG ! EX, CLIPFLAGS |= tmp (T << 2)
mov.l VTX,@-DST ! LS, dst->flags = PVR_CMD_VERTEX
.endm
.macro ProcessVertex4
fmov.s F_Z,@-DST ! LS, dst->z = Z
or EOS,FLG ! EX, CLIPFLAGS |= PVR_CMD_VERTEX_EOL
fmov.s F_C,@-DST ! LS, dst->c = C
fmov.s F_V,@-DST ! LS, dst->v = V
fcmp/gt ZERO, F_Z ! FE, T = Z > 0
fmov.s F_U,@-DST ! LS, dst->u = U
movt TMP ! EX, tmp = T
fmov.s F_W,@-DST ! LS, dst->w = W
shll2 TMP ! EX, tmp = tmp << 2
fmov.s F_Y,@-DST ! LS, dst->y = Y
add TMP,TMP ! EX, tmp = (tmp << 2) + (tmp << 2) (T << 3)
fmov.s F_X,@-DST ! LS, dst->x = X
or TMP,FLG ! EX, CLIPFLAGS |= tmp (T << 3)
mov.l FLG,@-DST ! LS, dst->flags = PVR_CMD_VERTEX_EOL | CLIPFLAGS
.endm
! =========================================================
! ==================== TEXTURED VERTEX TRANSFORM ==========
! =========================================================
.global _DrawTexturedQuads
.align 4
_DrawTexturedQuads:
! Setup
TransformSetup
.T_TRANSFORM_QUAD:
LoadTexturedVertex
ProcessVertex1
LoadTexturedVertex
ProcessVertex2
LoadTexturedVertex
ProcessVertex3
LoadTexturedVertex
ProcessVertex4
! CLIPFLAGS TESTING
and #15,FLG
cmp/eq #0,FLG ! T = CLIPFLAGS == 0 (all points invisible)
bf/s .T_LOOP_END ! if !T goto LOOP_END
nop
! No points visible case
add #-128, DST ! DST -= 4 * sizeof(VERTEX), move back to prior quad, so that this invisible quad gets overwritten in next iteration
.T_LOOP_END:
dt CNT ! count--; T = count == 0
bf .T_TRANSFORM_QUAD ! if !T then goto T_TRANSFORM_QUAD
nop
TransformEnd
.size _DrawTexturedQuads, .-_DrawTexturedQuads
.type _DrawTexturedQuads, %function
! =========================================================
! ==================== COLOURED VERTEX TRANSFORM ==========
! =========================================================
.global _DrawColouredQuads
.align 4
_DrawColouredQuads:
! Setup
fldi0 F_U ! U = 0
fldi0 F_V ! V = 0
TransformSetup
.C_TRANSFORM_QUAD:
LoadColouredVertex
ProcessVertex1
LoadColouredVertex
ProcessVertex2
LoadColouredVertex
ProcessVertex3
LoadColouredVertex
ProcessVertex4
! CLIPFLAGS TESTING
and #15,FLG
cmp/eq #0,FLG ! T = CLIPFLAGS == 0 (all points invisible)
bf/s .C_LOOP_END ! if !T goto LOOP_END
nop
! No points visible case
add #-128, DST ! dst -= 4 * sizeof(VERTEX), move back to 1 vertex before start of quad
.C_LOOP_END:
dt CNT ! count--; T = count == 0
bf .C_TRANSFORM_QUAD ! if !T then goto TRANSFORM_QUAD
nop
TransformEnd
.size _DrawColouredQuads, .-_DrawColouredQuads
.type _DrawColouredQuads, %function

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

3
misc/dreamcast/ip.txt Normal file
View File

@@ -0,0 +1,3 @@
Version : V1.360
SW Maker Name : ClassiCube team
Game Title : ClassiCube

View File

@@ -0,0 +1,9 @@
The dreamcast build requires an initial bootstrap program (Initial Program) named IP.bin
To generate a custom IP.bin, compile https://github.com/Dreamcast-Projects/makeip
Then run: makeip ip.txt IP.BIN -l boot_logo.png
---
For more details about IP.bin, see https://mc.pp.se/dc/ip.bin.html

View File

@@ -0,0 +1,31 @@
=========================================================
======================== PROCESSOR INFO =================
=========================================================
The SH4 can dual issue (i.e. parallel execution) two instructions
as long as the groups of the two instructions are different:
* LS - most ALU and FPU register load/stores
* EX - most ALU arithmetic instructions
* MT - TST, CMP, NOP, MOV Rm,Rn (NOTE: Can execute in parallel with other MT)
* FE - most FPU arithmetic instructions
* CO - other instructions (NOTE: Cannot never execute in parallel)
The following general aspects of instructions are important to note per the SH4 manual:
* Issue rate: Interval between the issue of an instruction and that of the next instruction
* Latency: Interval between the issue of an instruction and the generation of its result (completion)
* Latency is also the interval between the execution of two instructions with an interdependent relationship.
(although different cases may either increase or decrease Latency)
=========================================================
======================== REGISTER USAGES ================
=========================================================
SH4 C ABI:
- R0 to R3 are return values (can be overwritten)
- R4 to R7 are input arguments (can be overwritten)
- R8 to R13 are non-volatile (must be restored at end)
- R14 is the frame pointer (must be restored at end)
- R15 is the stack pointer (must be restored at end)
- FR0 to FR3 are return values (can be overwritten)
- FR4 to FR11 are input arguments (can be overwritten)
- FR12 to FR13 are non-volatile (must be restored at end)

60
misc/ds/Makefile Normal file
View File

@@ -0,0 +1,60 @@
# SPDX-License-Identifier: CC0-1.0
#
# SPDX-FileContributor: Antonio Niño Díaz, 2023
export BLOCKSDS ?= /opt/wonderful/thirdparty/blocksds/core
export BLOCKSDSEXT ?= /opt/wonderful/thirdparty/blocksds/external
GAME_TITLE := ClassiCube
GAME_SUBTITLE := Built with BlocksDS
GAME_AUTHOR := ClassiCube team
GAME_ICON := misc/ds/icon.bmp
GAME_FULL_TITLE := $(GAME_TITLE);$(GAME_SUBTITLE);$(GAME_AUTHOR)
# DLDI and internal SD slot of DSi
# --------------------------------
# Root folder of the SD image
SDROOT := sdroot
# Name of the generated image it "DSi-1.sd" for no$gba in DSi mode
SDIMAGE := image.bin
# Build artfacts
# --------------
ifdef BUILD_DSI
BUILDDIR := build/dsi
ROM := ClassiCube-dsi.nds
else
BUILDDIR := build/nds
ROM := ClassiCube-nds.nds
endif
# Targets
# -------
.PHONY: all clean arm9 arm7 dldipatch sdimage
all: $(ROM)
clean:
$(MAKE) -f Makefile.arm9 clean --no-print-directory
$(MAKE) -f Makefile.arm7 clean --no-print-directory
$(RM) $(ROM) $(BUILDDIR) $(SDIMAGE)
arm9:
$(MAKE) -f misc/ds/Makefile.arm9 --no-print-directory
arm7:
$(MAKE) -f misc/ds/Makefile.arm7 --no-print-directory
$(ROM): arm9 arm7
$(BLOCKSDS)/tools/ndstool/ndstool -c $@ \
-7 $(BUILDDIR)/cc-arm7.elf -9 $(BUILDDIR)/cc-arm9.elf \
-b $(GAME_ICON) "$(GAME_FULL_TITLE)"
sdimage:
$(BLOCKSDS)/tools/mkfatimg/mkfatimg -t $(SDROOT) $(SDIMAGE)
dldipatch: $(ROM)
$(BLOCKSDS)/tools/dlditool/dlditool $(BLOCKSDS)/tools/dldi/r4tfv2.dldi $(ROM)

96
misc/ds/Makefile.arm7 Normal file
View File

@@ -0,0 +1,96 @@
# SPDX-License-Identifier: CC0-1.0
#
# SPDX-FileContributor: Antonio Niño Díaz, 2023
export BLOCKSDS ?= /opt/wonderful/thirdparty/blocksds/core
export BLOCKSDSEXT ?= /opt/wonderful/thirdparty/blocksds/external
export WONDERFUL_TOOLCHAIN ?= /opt/wonderful
ARM_NONE_EABI_PATH ?= $(WONDERFUL_TOOLCHAIN)/toolchain/gcc-arm-none-eabi/bin/
SOURCEDIRS := misc/ds
INCLUDEDIRS :=
DSIWIFI := third_party/dsiwifi
ifdef BUILD_DSI
SOURCEDIRS += $(DSIWIFI)/arm_iop/source $(DSIWIFI)/common/source $(DSIWIFI)/arm_iop/source/ath $(DSIWIFI)/arm_iop/source/crypto $(DSIWIFI)/arm_iop/source/ieee
INCLUDEDIRS += $(DSIWIFI)/arm_iop/source $(DSIWIFI)/arm_iop/include $(DSIWIFI)/common/source $(DSIWIFI)/include $(DSIWIFI)/include/lwip
BUILDDIR := build/dsi
LIBS := -lc -lnds7
LIBDIRS := $(BLOCKSDS)/libs/libnds
else
BUILDDIR := build/nds
LIBS := -lc -lnds7 -ldswifi7
LIBDIRS := $(BLOCKSDS)/libs/libnds $(BLOCKSDS)/libs/dswifi
endif
NAME := cc-arm7
ELF := $(BUILDDIR)/$(NAME).elf
MAP := $(BUILDDIR)/$(NAME).map
PREFIX := $(ARM_NONE_EABI_PATH)arm-none-eabi-
CC := $(PREFIX)gcc
CXX := $(PREFIX)g++
LD := $(CC)
DEFINES := -D__NDS__ -DARM7
ARCH := -mcpu=arm7tdmi -mtune=arm7tdmi
WARNFLAGS := -Wall
# Source files
# ------------
S_FILES := $(foreach dir,$(SOURCEDIRS),$(wildcard $(dir)/*.s))
C_FILES := $(foreach dir,$(SOURCEDIRS),$(wildcard $(dir)/*.c))
INCLUDEFLAGS := $(foreach path,$(INCLUDEDIRS),-I$(path)) \
$(foreach path,$(LIBDIRS),-I$(path)/include)
LIBDIRSFLAGS := $(foreach path,$(LIBDIRS),-L$(path)/lib)
ASFLAGS += -x assembler-with-cpp $(DEFINES) $(ARCH) \
-mthumb -mthumb-interwork $(INCLUDEFLAGS) \
-ffunction-sections -fdata-sections
CFLAGS += -std=gnu11 $(WARNFLAGS) $(DEFINES) $(ARCH) \
-mthumb -mthumb-interwork $(INCLUDEFLAGS) -O2 \
-ffunction-sections -fdata-sections \
-fomit-frame-pointer
LDFLAGS := -mthumb -mthumb-interwork $(LIBDIRSFLAGS) \
-Wl,-Map,$(MAP) -Wl,--gc-sections -nostdlib \
-T$(BLOCKSDS)/sys/crts/ds_arm7.ld \
-Wl,--no-warn-rwx-segments \
-Wl,--start-group $(LIBS) -lgcc -Wl,--end-group
# Intermediate build files
# ------------------------
OBJS := $(addprefix $(BUILDDIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.s=%.o)))
DEPS := $(OBJS:.o=.d)
export VPATH := $(SOURCEDIRS)
# Targets
# -------
.PHONY: all clean
all: $(BUILDDIR) $(ELF)
$(BUILDDIR):
mkdir -p $(BUILDDIR)
$(ELF): $(OBJS)
$(LD) -o $@ $(OBJS) $(BLOCKSDS)/sys/crts/ds_arm7_crt0.o $(LDFLAGS)
clean:
rm $(ELF) $(MAP) $(OBJS)
# Rules
# -----
$(BUILDDIR)/%.o : %.s
$(CC) $(ASFLAGS) -MMD -MP -c -o $@ $<
$(BUILDDIR)/%.o : %.c
$(CC) $(CFLAGS) -MMD -MP -c -o $@ $<
# Include dependency files if they exist
# --------------------------------------
-include $(DEPS)

106
misc/ds/Makefile.arm9 Normal file
View File

@@ -0,0 +1,106 @@
# SPDX-License-Identifier: CC0-1.0
#
# SPDX-FileContributor: Antonio Niño Díaz, 2023
export BLOCKSDS ?= /opt/wonderful/thirdparty/blocksds/core
export BLOCKSDSEXT ?= /opt/wonderful/thirdparty/blocksds/external
export WONDERFUL_TOOLCHAIN ?= /opt/wonderful
ARM_NONE_EABI_PATH ?= $(WONDERFUL_TOOLCHAIN)/toolchain/gcc-arm-none-eabi/bin/
SOURCEDIRS := src
INCLUDEDIRS :=
DSIWIFI := third_party/dsiwifi
ifdef BUILD_DSI
SOURCEDIRS += $(DSIWIFI)/arm_host/source $(DSIWIFI)/common/source $(DSIWIFI)/arm_host/source/nds $(DSIWIFI)/arm_host/source/lwip $(DSIWIFI)/arm_host/source/lwip/ipv4 $(DSIWIFI)/arm_host/source/lwip/ipv6 $(DSIWIFI)/arm_host/source/lwip/netif $(DSIWIFI)/arm_host/source/lwip/netif/ppp $(DSIWIFI)/arm_host/source/lwip/api
INCLUDEDIRS += $(DSIWIFI)/arm_host/include $(DSIWIFI)/common/source $(DSIWIFI)/include $(DSIWIFI)/include/lwip
BUILDDIR := build/dsi
DEFINES := -DPLAT_NDS -DBUILD_DSI
LIBS := -lnds9 -lc
LIBDIRS := $(BLOCKSDS)/libs/libnds
else
BUILDDIR := build/nds
DEFINES := -DPLAT_NDS
LIBS := -ldswifi9 -lnds9 -lc
LIBDIRS := $(BLOCKSDS)/libs/dswifi $(BLOCKSDS)/libs/libnds
endif
NAME := cc-arm9
ELF := $(BUILDDIR)/$(NAME).elf
MAP := $(BUILDDIR)/$(NAME).map
# Tools
# -----
PREFIX := $(ARM_NONE_EABI_PATH)arm-none-eabi-
CC := $(PREFIX)gcc
CXX := $(PREFIX)g++
LD := $(PREFIX)gcc
# Source files
# ------------
S_FILES := $(foreach dir,$(SOURCEDIRS),$(wildcard $(dir)/*.s))
C_FILES := $(foreach dir,$(SOURCEDIRS),$(wildcard $(dir)/*.c))
# Compiler and linker flags
# -------------------------
ARCH := -mthumb -mcpu=arm946e-s+nofp
SPECS := $(BLOCKSDS)/sys/crts/ds_arm9.specs
WARNFLAGS := -Wall
INCLUDEFLAGS := $(foreach path,$(INCLUDEDIRS),-I$(path)) \
$(foreach path,$(LIBDIRS),-I$(path)/include)
LIBDIRSFLAGS := $(foreach path,$(LIBDIRS),-L$(path)/lib)
ASFLAGS += -x assembler-with-cpp $(DEFINES) $(INCLUDEFLAGS) \
$(ARCH) -ffunction-sections -fdata-sections \
-specs=$(SPECS)
CFLAGS += -std=gnu17 $(WARNFLAGS) $(DEFINES) $(INCLUDEFLAGS) \
$(ARCH) -O2 -ffunction-sections -fdata-sections \
-specs=$(SPECS) -Wstack-usage=10000
LDFLAGS := $(ARCH) $(LIBDIRSFLAGS) -Wl,-Map,$(MAP) $(DEFINES) \
-Wl,--start-group $(LIBS) -Wl,--end-group -specs=$(SPECS)
# Intermediate build files
# ------------------------
OBJS := $(addprefix $(BUILDDIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.s=%.o)))
DEPS := $(OBJS:.o=.d)
export VPATH := $(SOURCEDIRS)
# Targets
# -------
.PHONY: all
all: $(BUILDDIR) $(ELF)
$(BUILDDIR):
mkdir -p $(BUILDDIR)
$(ELF): $(OBJS)
$(LD) -o $@ $(OBJS) $(LDFLAGS)
clean:
rm $(ELF) $(MAP) $(OBJS)
rm -rf $(BUILDDIR)
# Rules
# -----
$(BUILDDIR)/%.o : %.s
$(CC) $(ASFLAGS) -MMD -MP -c -o $@ $<
$(BUILDDIR)/%.o : %.c
$(CC) $(CFLAGS) -MMD -MP -c -o $@ $<
$(BUILDDIR)/%.arm.o : %.arm.c
$(CC) $(CFLAGS) -MMD -MP -marm -mlong-calls -c -o $@ $<
# Include dependency files if they exist
# --------------------------------------
-include $(DEPS)

BIN
misc/ds/icon.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

54
misc/ds/main_arm7.c Normal file
View File

@@ -0,0 +1,54 @@
// SPDX-License-Identifier: Zlib
//
// Copyright (C) 2005 Michael Noland (joat)
// Copyright (C) 2005 Jason Rogers (Dovoto)
// Copyright (C) 2005-2015 Dave Murphy (WinterMute)
// Copyright (C) 2023 Antonio Niño Díaz
// Default ARM7 core
#include <dswifi7.h>
#include <nds.h>
volatile bool exit_loop = false;
static void power_button_callback(void) {
exit_loop = true;
}
static void vblank_handler(void) {
inputGetAndSend();
Wifi_Update();
}
int main(int argc, char *argv[]) {
enableSound();
readUserSettings();
ledBlink(0);
touchInit();
irqInit();
irqSet(IRQ_VBLANK, vblank_handler);
fifoInit();
installWifiFIFO();
installSoundFIFO();
installSystemFIFO();
setPowerButtonCB(power_button_callback);
initClockIRQTimer(3);
irqEnable(IRQ_VBLANK | IRQ_RTC);
while (!exit_loop)
{
const uint16_t key_mask = KEY_SELECT | KEY_START | KEY_L | KEY_R;
uint16_t keys_pressed = ~REG_KEYINPUT;
if ((keys_pressed & key_mask) == key_mask)
exit_loop = true;
swiWaitForVBlank();
}
return 0;
}

View File

@@ -0,0 +1,7 @@
#!/bin/sh
# Fallback Texture Pack and Audio
mkdir -p ${XDG_DATA_HOME}/ClassiCube/texpacks ${XDG_DATA_HOME}/ClassiCube/audio
test -f ${XDG_DATA_HOME}/ClassiCube/texpacks/classicube.zip || cp /app/share/classicube-texpack.zip ${XDG_DATA_HOME}/ClassiCube/texpacks/classicube.zip
test -f ${XDG_DATA_HOME}/ClassiCube/audio/classicube.zip || cp /app/share/classicube-audio.zip ${XDG_DATA_HOME}/ClassiCube/audio/classicube.zip
cd ${XDG_DATA_HOME}/ClassiCube && exec ClassiCube "$@"

View File

@@ -0,0 +1,136 @@
{
"id": "net.classicube.flatpak.client",
"runtime": "org.gnome.Platform",
"runtime-version": "48",
"sdk": "org.gnome.Sdk",
"command": "ClassiCubeLauncher",
"finish-args": [
"--socket=wayland",
"--socket=fallback-x11",
"--device=dri",
"--share=network",
"--share=ipc",
"--socket=pulseaudio"
],
"modules": [
{
"name": "SDL3",
"buildsystem": "cmake-ninja",
"builddir": true,
"sources": [
{
"type": "git",
"url": "https://github.com/libsdl-org/SDL.git",
"branch": "main"
}
],
"cleanup": [
"/bin/sdl3-config",
"/include",
"/lib/libSDL3.la",
"/lib/libSDL3main.a",
"/lib/libSDL3main.la",
"/lib/libSDL3_test.a",
"/lib/libSDL3_test.la",
"/lib/cmake",
"/share/aclocal",
"/lib/pkgconfig"
],
"modules": [
{
"name": "libdecor",
"buildsystem": "meson",
"config-opts": [
"-Ddemo=false"
],
"sources": [
{
"type": "git",
"url": "https://gitlab.freedesktop.org/libdecor/libdecor.git"
}
],
"cleanup": [
"/include",
"/lib/pkgconfig"
]
}
]
},
{
"name": "zenity-gtk3",
"buildsystem": "meson",
"build-commands": [
"mkdir -p ${FLATPAK_DEST}/share/icons/hicolor"
],
"sources": [
{
"type": "archive",
"url": "https://gitlab.gnome.org/GNOME/zenity/-/archive/3.44.4/zenity-3.44.4.tar.gz",
"sha256": "e7b334867d4e11053e6e52e5d51b7a983dc549f93cb3fda757e40309b16bc57b"
}
],
"post-install": [
"mv ${FLATPAK_DEST}/bin/zenity ${FLATPAK_DEST}/bin/zenity-gtk3"
]
},
{
"name": "zenity-gtk4",
"buildsystem": "meson",
"sources": [
{
"type": "archive",
"url": "https://gitlab.gnome.org/GNOME/zenity/-/archive/4.0.2/zenity-4.0.2.tar.gz",
"sha256": "fdbb74e882a6a56bb2f1a2381b81e08b06c627cc7e944edb71d107092c70dd80",
"x-checker-data": {
"type": "gnome",
"name": "zenity"
}
}
],
"post-install": [
"mv ${FLATPAK_DEST}/bin/zenity ${FLATPAK_DEST}/bin/zenity-gtk4"
]
},
{
"name": "ClassiCubeAssets",
"buildsystem": "simple",
"build-commands": [
"install -Dm644 classicube-texpack.zip ${FLATPAK_DEST}/share/classicube-texpack.zip",
"install -Dm644 classicube-audio.zip ${FLATPAK_DEST}/share/classicube-audio.zip"
],
"sources": [
{
"type": "file",
"dest-filename": "classicube-texpack.zip",
"url": "https://classicube.net/static/default.zip",
"sha256": "55eac12a9727d209b42694d07dfdca8d50349779ab77ffc11a31d2cb66b45635"
},
{
"type": "file",
"dest-filename": "classicube-audio.zip",
"url": "https://classicube.net/static/audio.zip",
"sha256": "13562a712d1cb1de3f36dd93a03245a377f201e7934d19c17de09202b410e04b"
}
]
},
{
"name": "ClassiCube",
"buildsystem": "simple",
"build-commands": [
"gcc -fno-math-errno src/*.c -o src/ClassiCube -rdynamic -lpthread -lGL -DCC_WIN_BACKEND=CC_WIN_BACKEND_SDL3 -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -DCC_BUILD_FLATPAK -L /app/lib -lSDL3",
"install -Dm755 src/ClassiCube -t ${FLATPAK_DEST}/bin",
"install -Dm755 misc/flatpak/ClassiCubeLauncher -t ${FLATPAK_DEST}/bin",
"install -Dm755 misc/flatpak/zenity-wrapper ${FLATPAK_DEST}/bin/zenity",
"install -Dm644 misc/flatpak/net.classicube.flatpak.client.svg ${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/net.classicube.flatpak.client.svg",
"install -Dm644 misc/flatpak/net.classicube.flatpak.client.desktop ${FLATPAK_DEST}/share/applications/net.classicube.flatpak.client.desktop",
"install -Dm644 misc/flatpak/net.classicube.flatpak.client.metainfo.xml ${FLATPAK_DEST}/share/metainfo/net.classicube.flatpak.client.metainfo.xml"
],
"sources": [
{
"type": "git",
"url": "https://github.com/ClassiCube/ClassiCube.git"
}
]
}
]
}

View File

@@ -0,0 +1,56 @@
{
"id": "net.classicube.flatpak.client",
"runtime": "org.freedesktop.Platform",
"runtime-version": "24.08",
"sdk": "org.freedesktop.Sdk",
"command": "ClassiCubeLauncher",
"finish-args": [
"--socket=x11",
"--device=dri",
"--share=network",
"--share=ipc",
"--socket=pulseaudio"
],
"modules": [
{
"name": "ClassiCubeAssets",
"buildsystem": "simple",
"build-commands": [
"install -Dm644 classicube-texpack.zip ${FLATPAK_DEST}/share/classicube-texpack.zip",
"install -Dm644 classicube-audio.zip ${FLATPAK_DEST}/share/classicube-audio.zip"
],
"sources": [
{
"type": "file",
"dest-filename": "classicube-texpack.zip",
"url": "https://classicube.net/static/default.zip",
"sha256": "55eac12a9727d209b42694d07dfdca8d50349779ab77ffc11a31d2cb66b45635"
},
{
"type": "file",
"dest-filename": "classicube-audio.zip",
"url": "https://classicube.net/static/audio.zip",
"sha256": "13562a712d1cb1de3f36dd93a03245a377f201e7934d19c17de09202b410e04b"
}
]
},
{
"name": "ClassiCube",
"buildsystem": "simple",
"build-commands": [
"gcc -fno-math-errno src/*.c -o src/ClassiCube -O1 -DCC_BUILD_FLATPAK -DCC_GFX_BACKEND=CC_GFX_BACKEND_GL2 -rdynamic -lm -lpthread -lX11 -lXi -lGL -ldl",
"install -Dm755 src/ClassiCube -t ${FLATPAK_DEST}/bin",
"install -Dm755 misc/flatpak/ClassiCubeLauncher -t ${FLATPAK_DEST}/bin",
"install -Dm644 misc/flatpak/net.classicube.flatpak.client.svg ${FLATPAK_DEST}/share/icons/hicolor/scalable/apps/net.classicube.flatpak.client.svg",
"install -Dm644 misc/flatpak/net.classicube.flatpak.client.desktop ${FLATPAK_DEST}/share/applications/net.classicube.flatpak.client.desktop",
"install -Dm644 misc/flatpak/net.classicube.flatpak.client.metainfo.xml ${FLATPAK_DEST}/share/metainfo/net.classicube.flatpak.client.metainfo.xml"
],
"sources": [
{
"type": "git",
"url": "https://github.com/ClassiCube/ClassiCube.git"
}
]
}
]
}

View File

@@ -0,0 +1,10 @@
[Desktop Entry]
Name=ClassiCube
Exec=ClassiCubeLauncher
Comment=Sandbox building-block game
Type=Application
Icon=net.classicube.flatpak.client
Categories=Game;ActionGame;
Terminal=false
MimeType=x-scheme-handler/mc;
StartupWMClass=net.classicube.flatpak.client

View File

@@ -0,0 +1,133 @@
<?xml version='1.0' encoding='utf-8'?>
<component type="desktop-application">
<id>net.classicube.flatpak.client</id>
<name>ClassiCube</name>
<summary>Sandbox building-block game</summary>
<developer id="net.classicube">
<name>The ClassiCube Project</name>
</developer>
<metadata_license>CC0-1.0</metadata_license>
<project_license>BSD-3-Clause</project_license>
<description>
<p>ClassiCube brings you back to the days of 2009 where one block game ruled them all, it includes such features as:</p>
<ul>
<li>Loads of blocks and items to choose from</li>
<li>Chatting with other players</li>
<li>An extremely simple network protocol to tinker with</li>
<li>Hundreds of creative and inventive worlds to explore online</li>
<li>A growing community</li>
<li>Hundreds of hours of entertainment</li>
</ul>
</description>
<screenshots>
<screenshot type="default">
<caption>Classic mode features faithful classic gameplay</caption>
<image type="source">https://github.com/ClassiCube/ClassiCube/assets/6509348/eedee53f-f53e-456f-b51c-92c62079eee0</image>
</screenshot>
<screenshot>
<caption>Enhanced mode allows hacks like flying and noclipping, it also allows servers to provide many custom features</caption>
<image type="source">https://github.com/ClassiCube/ClassiCube/assets/6509348/b2fe0e2b-5d76-41ab-909f-048d0ad15f37</image>
</screenshot>
</screenshots>
<releases>
<release version="1.3.6" date="2023-08-28" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.6</url>
</release>
<release version="1.3.5" date="2023-01-06" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.5</url>
</release>
<release version="1.3.4" date="2022-11-01" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.4</url>
</release>
<release version="1.3.3" date="2022-10-08" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.3</url>
</release>
<release version="1.3.2" date="2022-05-26" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.2</url>
</release>
<release version="1.3.1" date="2022-01-11" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.1</url>
</release>
<release version="1.3.0" date="2022-01-04" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.3.0</url>
</release>
<release version="1.2.9" date="2021-10-18" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.9</url>
</release>
<release version="1.2.8" date="2021-09-18" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.8</url>
</release>
<release version="1.2.7" date="2021-07-22" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.7</url>
</release>
<release version="1.2.6" date="2021-07-02" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.6</url>
</release>
<release version="1.2.5" date="2021-04-02" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.5</url>
</release>
<release version="1.2.4" date="2021-01-23" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.4</url>
</release>
<release version="1.2.3" date="2020-12-12" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.3</url>
</release>
<release version="1.2.2" date="2020-12-11" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.2</url>
</release>
<release version="1.2.1" date="2020-11-28" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.1</url>
</release>
<release version="1.2.0" date="2020-10-01" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.2.0</url>
</release>
<release version="1.1.9" date="2020-08-16" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.9</url>
</release>
<release version="1.1.8" date="2020-08-05" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.8</url>
</release>
<release version="1.1.7" date="2020-06-13" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.7</url>
</release>
<release version="1.1.6" date="2020-05-07" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.6</url>
</release>
<release version="1.1.5" date="2020-05-01" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.5</url>
</release>
<release version="1.1.4" date="2020-04-21" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.4</url>
</release>
<release version="1.1.3" date="2020-03-08" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.3</url>
</release>
<release version="1.1.2" date="2020-01-26" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.2</url>
</release>
<release version="1.1.1" date="2019-12-16" type="stable">
<url>https://github.com/ClassiCube/ClassiCube/releases/tag/1.1.1</url>
</release>
</releases>
<url type="homepage">https://www.classicube.net/</url>
<url type="bugtracker">https://github.com/ClassiCube/ClassiCube/issues</url>
<url type="donation">https://www.patreon.com/ClassiCube</url>
<url type="vcs-browser">https://github.com/ClassiCube/ClassiCube</url>
<categories>
<category>Game</category>
<category>AdventureGame</category>
<category>ActionGame</category>
</categories>
<recommends>
<control>pointing</control>
<control>keyboard</control>
</recommends>
<content_rating type="oars-1.1">
<content_attribute id="violence-cartoon">moderate</content_attribute>
<content_attribute id="social-chat">intense</content_attribute>
</content_rating>
<launchable type="desktop-id">net.classicube.flatpak.client.desktop</launchable>
<provides>
<binary>ClassiCube</binary>
</provides>
</component>

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="128"
height="127.99999"
viewBox="0 0 33.866667 33.866664"
version="1.1"
id="svg8"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
transform="translate(5.8338447,-13.20144)">
<g
id="g4741"
transform="matrix(0.12177585,0,0,0.12056875,-1.6325083,12.971524)">
<path
id="path4737"
d="M -5.8338447,207.40561 V 78.28894 L 106.61407,13.20144 218.79741,78.28894 V 207.40561 L 106.61407,272.4931 Z"
style="fill:#f6f6f6;stroke:#000000;stroke-width:8.0626;stroke-dasharray:none;stroke-opacity:1" />
<path
id="path179"
d="m 104.07502,141.52929 110.68965,-60.9215 1.62598,125.47985 -109.78346,61.73499 z m 20.61272,94.64566 c 8.561,-1.36503 22.58979,-6.90566 34.77207,-13.73314 8.44846,-4.73489 17.45957,-10.82064 25.81752,-17.43613 8.72093,-6.90281 17.22731,-15.21726 18.55921,-18.14047 0.26981,-0.59217 0.24879,-0.77358 -0.13391,-1.15568 -0.36305,-0.36248 -0.91552,-0.44887 -2.7589,-0.43139 -3.71393,0.0352 -9.27509,1.35366 -16.28846,3.86168 -2.01562,0.7208 -3.69686,1.27297 -3.73608,1.22704 -0.16881,-0.19764 3.44601,-29.37179 6.84564,-55.24912 1.21398,-9.24057 2.15592,-16.89033 2.09321,-16.99948 -0.19747,-0.34365 -6.05941,-0.21541 -8.74964,0.19141 -11.67357,1.7653 -26.1385,9.31897 -38.83406,20.27938 -3.00232,2.59198 -8.66363,8.37481 -10.38554,10.60847 l -1.13332,1.47013 1.06078,5.78494 c 1.66864,9.09991 3.21014,18.62874 5.55847,34.35994 1.6265,10.89577 2.70193,17.7159 2.81167,17.83099 0.23021,0.24143 9.15704,-3.22834 13.96159,-5.42672 4.01374,-1.83655 7.38001,-3.77497 13.6069,-7.83534 5.39432,-3.51748 6.57616,-4.09382 7.18285,-3.50281 1.32604,1.29178 -3.92898,6.46583 -11.75312,11.57204 -5.59387,3.65069 -11.90727,6.67998 -18.54423,8.8979 -3.61228,1.20714 -3.99351,1.40207 -6.48521,3.316 -7.13359,5.47947 -15.77323,13.5129 -18.33378,17.04736 -1.39429,1.92461 -1.60126,3.07547 -0.62376,3.46838 0.81553,0.3278 3.41645,0.32525 5.4901,-0.005 z"
style="fill:#cbcbcb;fill-opacity:1;stroke-width:0.264583" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# Allow forcing GTK3/4 through $CC_DIALOG_FORCE_ZENITY_GTK{3,4}
if [[ -z "${CC_DIALOG_FORCE_ZENITY_GTK3}" && "${XDG_CURRENT_DESKTOP}" == "GNOME" || ! -z "${CC_DIALOG_FORCE_ZENITY_GTK4}" ]]; then
zenity-gtk4 "$@"
else
zenity-gtk3 "$@"
fi

88
misc/gba/Makefile Normal file
View File

@@ -0,0 +1,88 @@
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>devkitPro)
endif
include $(DEVKITPRO)/devkitARM/gba_rules
#---------------------------------------------------------------------------------
# Configurable options
#---------------------------------------------------------------------------------
# Name of the final output
TARGET = ClassiCube-gba
# List of directories containing source code
SOURCE_DIRS = src src/gba
# Directory where object files are placed
BUILD_DIR = build/gba
GAME_TITLE = ClassiCube
GAME_CODE = 0000
MAKER_CODE = 00
#---------------------------------------------------------------------------------
# Code generation
#---------------------------------------------------------------------------------
S_FILES = $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.S))
C_FILES = $(foreach dir,$(SOURCE_DIRS),$(wildcard $(dir)/*.c))
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(C_FILES:%.c=%.o) $(S_FILES:%.S=%.o)))
ARCH = -mthumb -mthumb-interwork
CFLAGS = -g -Wall -O2 -DPLAT_GBA -ffunction-sections -fdata-sections -mcpu=arm7tdmi -mtune=arm7tdmi $(ARCH)
ASFLAGS = -g $(ARCH)
LDFLAGS = -specs=gba.specs -g $(ARCH)
LIBS = -ltonc
LIBGBA := $(DEVKITPRO)/libgba
INCLUDES += $(foreach dir, $(LIBGBA), -I$(dir)/include)
LDFLAGS += $(foreach dir, $(LIBGBA), -L$(dir)/lib)
LIBTONC = $(DEVKITPRO)/libtonc
INCLUDES += $(foreach dir, $(LIBTONC), -I$(dir)/include)
LDFLAGS += $(foreach dir, $(LIBTONC), -L$(dir)/lib)
# Dependency tracking
DEPFLAGS = -MT $@ -MMD -MP -MF $(BUILD_DIR)/$*.d
DEPFILES := $(OBJS:%.o=%.d)
#---------------------------------------------------------------------------------
# Main targets
#---------------------------------------------------------------------------------
default: $(BUILD_DIR) $(TARGET).gba
clean:
rm $(TARGET).gba $(TARGET).elf $(OBJS)
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
#---------------------------------------------------------------------------------
# Executable generation
#---------------------------------------------------------------------------------
$(TARGET).elf: $(OBJS)
$(CC) $(LDFLAGS) $^ -o $@ $(LIBS)
$(TARGET).gba: $(TARGET).elf
$(OBJCOPY) -O binary $< $@
gbafix $@ -t$(GAME_TITLE) -c$(GAME_CODE) -m$(MAKER_CODE)
#---------------------------------------------------------------------------------
# Object generation
#---------------------------------------------------------------------------------
$(BUILD_DIR)/%.o: src/%.c
$(CC) $(CFLAGS) $(INCLUDES) $(DEPFLAGS) -c $< -o $@
$(BUILD_DIR)/%.o: src/gba/%.c
$(CC) $(CFLAGS) $(INCLUDES) $(DEPFLAGS) -c $< -o $@
#---------------------------------------------------------------------------------
# Dependency tracking
#---------------------------------------------------------------------------------
$(DEPFILES):
include $(wildcard $(DEPFILES))

Some files were not shown because too many files have changed in this diff Show More