mirror of
https://github.com/XProger/OpenLara.git
synced 2025-08-05 12:47:53 +02:00
GBA initial commit
This commit is contained in:
167
src/platform/gba/Makefile
Normal file
167
src/platform/gba/Makefile
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/gba_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# TARGET is the name of the output
|
||||||
|
# BUILD is the directory where object files & intermediate files will be placed
|
||||||
|
# SOURCES is a list of directories containing source code
|
||||||
|
# INCLUDES is a list of directories containing extra header files
|
||||||
|
# DATA is a list of directories containing binary data
|
||||||
|
# GRAPHICS is a list of directories containing files to be processed by grit
|
||||||
|
#
|
||||||
|
# All directories are specified relative to the project directory where
|
||||||
|
# the makefile is found
|
||||||
|
#
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
TARGET := OpenLara
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := .
|
||||||
|
INCLUDES := include
|
||||||
|
DATA := data
|
||||||
|
MUSIC :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -mthumb -mthumb-interwork
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O3\
|
||||||
|
-mcpu=arm7tdmi -mtune=arm7tdmi\
|
||||||
|
-fomit-frame-pointer\
|
||||||
|
-ffast-math\
|
||||||
|
$(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE)
|
||||||
|
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# any extra libraries we wish to link with the project
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBS := -lmm -lgba
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBGBA)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# no real need to edit anything past this point unless you need to add additional
|
||||||
|
# rules for different file extensions
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
ifneq ($(strip $(MUSIC)),)
|
||||||
|
export AUDIOFILES := $(foreach dir,$(notdir $(wildcard $(MUSIC)/*.*)),$(CURDIR)/$(MUSIC)/$(dir))
|
||||||
|
BINFILES += soundbank.bin
|
||||||
|
endif
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||||
|
|
||||||
|
export OFILES_SOURCES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export OFILES := $(OFILES_BIN) $(OFILES_SOURCES)
|
||||||
|
|
||||||
|
export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) $(TARGET).elf $(TARGET).gba
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
$(OUTPUT).gba : $(OUTPUT).elf
|
||||||
|
|
||||||
|
$(OUTPUT).elf : $(OFILES)
|
||||||
|
|
||||||
|
$(OFILES_SOURCES) : $(HFILES)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# The bin2o rule should be copied and modified
|
||||||
|
# for each extension used in the data directories
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# rule to build soundbank from music files
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
soundbank.bin soundbank.h : $(AUDIOFILES)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@mmutil $^ -osoundbank.bin -hsoundbank.h
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# This rule links in binary data with the .bin extension
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.PHD.o %_PHD.h : %.PHD
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-include $(DEPSDIR)/*.d
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
31
src/platform/gba/OpenLara.sln
Normal file
31
src/platform/gba/OpenLara.sln
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio 15
|
||||||
|
VisualStudioVersion = 15.0.28307.1022
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenLara", "OpenLara.vcxproj", "{990C6F40-6226-4011-B52C-FF042EBB7F15}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|x64 = Debug|x64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|x64 = Release|x64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Release|x64.Build.0 = Release|x64
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{990C6F40-6226-4011-B52C-FF042EBB7F15}.Release|x86.Build.0 = Release|Win32
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {8D133CA9-7AA0-4806-9B61-82E8A3044A15}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
163
src/platform/gba/OpenLara.vcxproj
Normal file
163
src/platform/gba/OpenLara.vcxproj
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="common.iwram.cpp" />
|
||||||
|
<ClCompile Include="main.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="common.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<VCProjectVersion>15.0</VCProjectVersion>
|
||||||
|
<ProjectGuid>{990C6F40-6226-4011-B52C-FF042EBB7F15}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>OpenLara</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>NotSet</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>NotSet</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v141</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level2</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level2</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
269
src/platform/gba/common.h
Normal file
269
src/platform/gba/common.h
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
#ifndef H_COMMON
|
||||||
|
#define H_COMMON
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <gba_console.h>
|
||||||
|
#include <gba_video.h>
|
||||||
|
#include <gba_timers.h>
|
||||||
|
#include <gba_interrupt.h>
|
||||||
|
#include <gba_systemcalls.h>
|
||||||
|
#include <gba_input.h>
|
||||||
|
#include <gba_dma.h>
|
||||||
|
#include <gba_affine.h>
|
||||||
|
#include <fade.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
//#define USE_MODE_5
|
||||||
|
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
#define WIDTH 160
|
||||||
|
#define HEIGHT 128
|
||||||
|
#define FRAME_WIDTH 160
|
||||||
|
#define FRAME_HEIGHT 128
|
||||||
|
#define PIXEL_SIZE 1
|
||||||
|
#else // MODE_4
|
||||||
|
#define WIDTH 240
|
||||||
|
#define HEIGHT 160
|
||||||
|
#define FRAME_WIDTH 240
|
||||||
|
#define FRAME_HEIGHT 160
|
||||||
|
#define PIXEL_SIZE 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WND_SCALE 4
|
||||||
|
|
||||||
|
typedef signed char int8;
|
||||||
|
typedef signed short int16;
|
||||||
|
typedef signed int int32;
|
||||||
|
typedef signed long long int64;
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
typedef int16 Index;
|
||||||
|
|
||||||
|
#define PI 3.14159265358979323846f
|
||||||
|
#define PIH (PI * 0.5f)
|
||||||
|
#define PI2 (PI * 2.0f)
|
||||||
|
#define DEG2RAD (PI / 180.0f)
|
||||||
|
#define RAD2DEG (180.0f / PI)
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
extern uint8* LEVEL1_PHD;
|
||||||
|
|
||||||
|
extern uint32 VRAM[WIDTH * HEIGHT];
|
||||||
|
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
extern uint16 fb[WIDTH * HEIGHT];
|
||||||
|
#else
|
||||||
|
extern uint8 fb[WIDTH * HEIGHT];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define IWRAM_CODE
|
||||||
|
#define EWRAM_DATA
|
||||||
|
|
||||||
|
#define dmaCopy(src,dst,size) memcpy(dst,src,size)
|
||||||
|
#define ALIGN4
|
||||||
|
|
||||||
|
struct ObjAffineSource {
|
||||||
|
int16 sX;
|
||||||
|
int16 sY;
|
||||||
|
uint16 theta;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjAffineDest {
|
||||||
|
int16 pa;
|
||||||
|
int16 pb;
|
||||||
|
int16 pc;
|
||||||
|
int16 pd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void ObjAffineSet(ObjAffineSource *source, ObjAffineDest *dest, int32 num, int32 offset) {
|
||||||
|
float ang = (source->theta >> 8) * PI / 128.0f;
|
||||||
|
|
||||||
|
int32 c = int32(cosf(ang) * 16384.0f);
|
||||||
|
int32 s = int32(sinf(ang) * 16384.0f);
|
||||||
|
|
||||||
|
dest->pa = ( source->sX * c) >> 14;
|
||||||
|
dest->pb = (-source->sX * s) >> 14;
|
||||||
|
dest->pc = ( source->sY * s) >> 14;
|
||||||
|
dest->pd = ( source->sY * c) >> 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define ALIGN4 __attribute__ ((aligned (4)))
|
||||||
|
|
||||||
|
extern uint32 fb;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum InputKey {
|
||||||
|
IK_UP,
|
||||||
|
IK_RIGHT,
|
||||||
|
IK_DOWN,
|
||||||
|
IK_LEFT,
|
||||||
|
IK_A,
|
||||||
|
IK_B,
|
||||||
|
IK_L,
|
||||||
|
IK_R,
|
||||||
|
IK_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
extern bool keys[IK_MAX];
|
||||||
|
|
||||||
|
struct Quad {
|
||||||
|
Index indices[4];
|
||||||
|
uint16 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Triangle {
|
||||||
|
Index indices[3];
|
||||||
|
uint16 flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Room {
|
||||||
|
struct Info {
|
||||||
|
int32 x, z;
|
||||||
|
int32 yBottom, yTop;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
int16 x, y, z;
|
||||||
|
uint16 lighting;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sprite {
|
||||||
|
Index index;
|
||||||
|
uint16 texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Portal {
|
||||||
|
struct Vertex {
|
||||||
|
int16 x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16 roomIndex;
|
||||||
|
Vertex n;
|
||||||
|
Vertex v[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sector {
|
||||||
|
uint16 floorIndex;
|
||||||
|
uint16 boxIndex;
|
||||||
|
uint8 roomBelow;
|
||||||
|
int8 floor;
|
||||||
|
uint8 roomAbove;
|
||||||
|
int8 ceiling;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Light {
|
||||||
|
// int32 x, y, z;
|
||||||
|
// uint16 intensity;
|
||||||
|
// uint32 radius;
|
||||||
|
uint8 dummy[18];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Mesh {
|
||||||
|
// int32 x, y, z;
|
||||||
|
// uint16 rotation;
|
||||||
|
// uint16 intensity;
|
||||||
|
// uint16 meshID;
|
||||||
|
uint8 dummy[18];
|
||||||
|
};
|
||||||
|
|
||||||
|
Info info;
|
||||||
|
uint32 dataSize;
|
||||||
|
/*
|
||||||
|
uint16 vCount;
|
||||||
|
Vertex* vertices;
|
||||||
|
|
||||||
|
uint16 qCount;
|
||||||
|
Quad* quads;
|
||||||
|
|
||||||
|
uint16 tCount;
|
||||||
|
Triangle* triangles;
|
||||||
|
|
||||||
|
uint16 sCount;
|
||||||
|
Sprite* sprites;
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node {
|
||||||
|
uint32 flags;
|
||||||
|
int32 x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Model {
|
||||||
|
uint16 type;
|
||||||
|
uint16 index;
|
||||||
|
uint16 mCount;
|
||||||
|
uint16 mStart;
|
||||||
|
uint32 node;
|
||||||
|
uint32 frame;
|
||||||
|
uint16 animation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Texture {
|
||||||
|
uint16 attribute;
|
||||||
|
uint16 tile:14, :2;
|
||||||
|
uint8 xh0, x0, yh0, y0;
|
||||||
|
uint8 xh1, x1, yh1, y1;
|
||||||
|
uint8 xh2, x2, yh2, y2;
|
||||||
|
uint8 xh3, x3, yh3, y3;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Sprite {
|
||||||
|
uint16 tile;
|
||||||
|
uint8 u, v;
|
||||||
|
uint16 w, h;
|
||||||
|
int16 l, t, r, b;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpriteSequence {
|
||||||
|
uint16 type;
|
||||||
|
uint16 unused;
|
||||||
|
int16 sCount;
|
||||||
|
int16 sStart;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Rect {
|
||||||
|
int32 x0;
|
||||||
|
int32 y0;
|
||||||
|
int32 x1;
|
||||||
|
int32 y1;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex {
|
||||||
|
int16 x, y;
|
||||||
|
int16 z;
|
||||||
|
uint8 u, v, g, clip;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Face {
|
||||||
|
uint16 flags;
|
||||||
|
int16 depth;
|
||||||
|
int16 start;
|
||||||
|
int8 indices[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_VERTICES 1024
|
||||||
|
#define MAX_FACES 384
|
||||||
|
#define MAX_DIST (16 * 1024)
|
||||||
|
|
||||||
|
#define FACE_TRIANGLE 0x8000
|
||||||
|
#define FACE_COLORED 0x4000
|
||||||
|
#define FACE_TEXTURE 0x3FFF
|
||||||
|
|
||||||
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
|
void drawGlyph(int32 index, int32 x, int32 y);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
#endif
|
993
src/platform/gba/common.iwram.cpp
Normal file
993
src/platform/gba/common.iwram.cpp
Normal file
@@ -0,0 +1,993 @@
|
|||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#define DIV_TABLE_SIZE 512
|
||||||
|
|
||||||
|
uint16 divTable[DIV_TABLE_SIZE];
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
uint8* LEVEL1_PHD;
|
||||||
|
|
||||||
|
uint32 VRAM[WIDTH * HEIGHT];
|
||||||
|
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
uint16 fb[WIDTH * HEIGHT];
|
||||||
|
#else
|
||||||
|
uint8 fb[WIDTH * HEIGHT];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MyDiv(Number, Divisor) ((Number) / (Divisor))
|
||||||
|
#else
|
||||||
|
uint32 fb = VRAM;
|
||||||
|
|
||||||
|
#define MyDiv(Number, Divisor) ((Number) / (Divisor))
|
||||||
|
//#define MyDiv(Number, Divisor) Div(Number, Divisor)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FixedInvS(x) ((x < 0) ? -divTable[abs(x)] : divTable[x])
|
||||||
|
#define FixedInvU(x) divTable[x]
|
||||||
|
|
||||||
|
bool keys[IK_MAX] = {};
|
||||||
|
|
||||||
|
#if defined(USE_MODE_5) || defined(_WIN32)
|
||||||
|
uint16 palette[256];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8 lightmap[256 * 32];
|
||||||
|
|
||||||
|
Vertex gVertices[MAX_VERTICES];
|
||||||
|
uint32 gVerticesCount = 0;
|
||||||
|
|
||||||
|
EWRAM_DATA Face gFaces[MAX_FACES];
|
||||||
|
int32 gFacesCount = 0;
|
||||||
|
|
||||||
|
Rect clip;
|
||||||
|
|
||||||
|
const uint8* tiles[15];
|
||||||
|
|
||||||
|
const uint8* curTile;
|
||||||
|
|
||||||
|
uint16 mipMask;
|
||||||
|
|
||||||
|
int32 fps;
|
||||||
|
|
||||||
|
int32 camSinY;
|
||||||
|
int32 camCosY;
|
||||||
|
|
||||||
|
int32 camX = 75162;
|
||||||
|
int32 camY = 3072 - 1024;
|
||||||
|
int32 camZ = 5000;
|
||||||
|
|
||||||
|
Vertex* Ledges[4];
|
||||||
|
Vertex* Redges[4];
|
||||||
|
int32 Lindex, Rindex;
|
||||||
|
|
||||||
|
uint16 roomsCount;
|
||||||
|
const Room* rooms;
|
||||||
|
|
||||||
|
uint32 texturesCount;
|
||||||
|
const Texture* textures;
|
||||||
|
|
||||||
|
const Sprite* sprites;
|
||||||
|
|
||||||
|
uint32 spriteSequencesCount;
|
||||||
|
const SpriteSequence* spriteSequences;
|
||||||
|
|
||||||
|
int32 seqGlyphs;
|
||||||
|
|
||||||
|
const uint8* meshData;
|
||||||
|
const uint32* meshOffsets;
|
||||||
|
|
||||||
|
const int32* nodes;
|
||||||
|
const Model* models;
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define INLINE inline
|
||||||
|
#else
|
||||||
|
#define INLINE __attribute__((always_inline)) inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32 clamp(int32 x, int32 a, int32 b) {
|
||||||
|
return x < a ? a : (x > b ? b : x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void swap(T &a, T &b) {
|
||||||
|
T tmp = a;
|
||||||
|
a = b;
|
||||||
|
b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkBackface(const Vertex *a, const Vertex *b, const Vertex *c) {
|
||||||
|
return (b->x - a->x) * (c->y - a->y) -
|
||||||
|
(c->x - a->x) * (b->y - a->y) <= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void sortVertices(Vertex *&t, Vertex *&m, Vertex *&b) {
|
||||||
|
if (t->y > m->y) swap(t, m);
|
||||||
|
if (t->y > b->y) swap(t, b);
|
||||||
|
if (m->y > b->y) swap(m, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void sortVertices(Vertex *&t, Vertex *&m, Vertex *&o, Vertex *&b) {
|
||||||
|
if (t->y > m->y) swap(t, m);
|
||||||
|
if (o->y > b->y) swap(o, b);
|
||||||
|
if (t->y > o->y) swap(t, o);
|
||||||
|
if (m->y > b->y) swap(m, b);
|
||||||
|
if (m->y > o->y) swap(m, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 classify(const Vertex* v) {
|
||||||
|
return (v->x < clip.x0 ? 1 : 0) |
|
||||||
|
(v->x > clip.x1 ? 2 : 0) |
|
||||||
|
(v->y < clip.y0 ? 4 : 0) |
|
||||||
|
(v->y > clip.y1 ? 8 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void transform(int32 vx, int32 vy, int32 vz, int32 vg, int32 x, int32 y, int32 z) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (gVerticesCount >= MAX_VERTICES) {
|
||||||
|
DebugBreak();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Vertex &res = gVertices[gVerticesCount++];
|
||||||
|
|
||||||
|
int32 px = vx + x;
|
||||||
|
int32 pz = vz + z;
|
||||||
|
|
||||||
|
int32 cz = px * camSinY + pz * camCosY;
|
||||||
|
cz >>= 16;
|
||||||
|
|
||||||
|
// znear / zfar clip
|
||||||
|
if (cz < 32 || cz > MAX_DIST) {
|
||||||
|
res.z = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 py = vy + y;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int32 cx = (px * camCosY - pz * camSinY) >> 16;
|
||||||
|
int32 cy = py;
|
||||||
|
|
||||||
|
uint32 czInv = MyDiv(1 << 16, uint32(cz));
|
||||||
|
|
||||||
|
cx = cx * czInv;
|
||||||
|
cy = cy * czInv;
|
||||||
|
#else
|
||||||
|
int32 cx = px * camCosY - pz * camSinY;
|
||||||
|
int32 cy = py << 16;
|
||||||
|
|
||||||
|
cx = MyDiv(cx, cz);
|
||||||
|
cy = MyDiv(cy, cz);
|
||||||
|
#endif
|
||||||
|
cy = cy * FRAME_WIDTH / FRAME_HEIGHT;
|
||||||
|
|
||||||
|
cx = clamp(cx, -2 << 16, 2 << 16);
|
||||||
|
cy = clamp(cy, -2 << 16, 2 << 16);
|
||||||
|
|
||||||
|
res.x = ( ( (1 << 16) + cx ) * (FRAME_WIDTH / 2) ) >> 16;
|
||||||
|
res.y = ( ( (1 << 16) + cy ) * (FRAME_HEIGHT / 2) ) >> 16;
|
||||||
|
res.z = cz;
|
||||||
|
res.clip = classify(&res);
|
||||||
|
|
||||||
|
int32 fog = vg - ((cz * cz) >> 15);
|
||||||
|
if (fog < 0) {
|
||||||
|
fog = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.g = uint32(255 - (fog >> 5)) >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FETCH_T() curTile[(t & 0xFF00) | (t >> 24)]
|
||||||
|
#define FETCH_T_MIP() curTile[(t & 0xFF00) | (t >> 24) & mipMask]
|
||||||
|
#define FETCH_GT() lightmap[(g & 0x1F00) | FETCH_T()]
|
||||||
|
#define FETCH_G(palIndex) lightmap[(g & 0x1F00) | palIndex]
|
||||||
|
#define FETCH_GT_PAL() palette[FETCH_GT()]
|
||||||
|
#define FETCH_G_PAL(palIndex) palette[FETCH_G(palIndex)]
|
||||||
|
|
||||||
|
struct Edge {
|
||||||
|
int32 h;
|
||||||
|
int32 x;
|
||||||
|
int32 g;
|
||||||
|
uint32 t;
|
||||||
|
int32 dx;
|
||||||
|
int32 dg;
|
||||||
|
uint32 dt;
|
||||||
|
|
||||||
|
int32 index;
|
||||||
|
Vertex* vert[8];
|
||||||
|
|
||||||
|
Edge() : h(0), dx(0), dg(0), dt(0) {}
|
||||||
|
|
||||||
|
INLINE void stepG() {
|
||||||
|
x += dx;
|
||||||
|
g += dg;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void stepGT() {
|
||||||
|
x += dx;
|
||||||
|
g += dg;
|
||||||
|
t += dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE bool nextG() {
|
||||||
|
if (index == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex* v1 = vert[index--];
|
||||||
|
Vertex* v2 = vert[index];
|
||||||
|
|
||||||
|
h = v2->y - v1->y;
|
||||||
|
x = v1->x << 16;
|
||||||
|
g = v1->g << 16;
|
||||||
|
|
||||||
|
if (h > 1) {
|
||||||
|
uint32 d = FixedInvU(h);
|
||||||
|
|
||||||
|
dx = d * (v2->x - v1->x);
|
||||||
|
dg = d * (v2->g - v1->g);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE bool nextGT() {
|
||||||
|
if (index == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex* v1 = vert[index--];
|
||||||
|
Vertex* v2 = vert[index];
|
||||||
|
|
||||||
|
h = v2->y - v1->y;
|
||||||
|
x = v1->x << 16;
|
||||||
|
g = v1->g << 16;
|
||||||
|
t = (v1->u << 24) | (v1->v << 8);
|
||||||
|
|
||||||
|
if (h > 1) {
|
||||||
|
uint32 d = FixedInvU(h);
|
||||||
|
|
||||||
|
dx = d * (v2->x - v1->x);
|
||||||
|
dg = d * (v2->g - v1->g);
|
||||||
|
|
||||||
|
int32 du = d * (v2->u - v1->u);
|
||||||
|
int32 dv = d * (v2->v - v1->v);
|
||||||
|
|
||||||
|
dt = ((du << 8) & 0xFFFF0000) | int16(dv >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
INLINE void scanlineG(uint16* buffer, int32 x1, int32 x2, uint8 palIndex, uint32 g, int32 dgdx) {
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
uint16* pixel = buffer + x1;
|
||||||
|
int32 width = (x2 - x1);
|
||||||
|
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
*pixel++ = FETCH_G_PAL(palIndex);
|
||||||
|
g += dgdx;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (x1 & 1)
|
||||||
|
{
|
||||||
|
uint16 &p = *(uint16*)((uint8*)buffer + x1 - 1);
|
||||||
|
p = (p & 0x00FF) | (FETCH_G(palIndex) << 8);
|
||||||
|
g += dgdx;
|
||||||
|
x1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 width = (x2 - x1) >> 1;
|
||||||
|
uint16* pixel = (uint16*)((uint8*)buffer + x1);
|
||||||
|
|
||||||
|
dgdx <<= 1;
|
||||||
|
|
||||||
|
if (width && (x1 & 3))
|
||||||
|
{
|
||||||
|
uint16 p = FETCH_G(palIndex);
|
||||||
|
*pixel++ = p | (FETCH_G(palIndex) << 8);
|
||||||
|
|
||||||
|
g += dgdx;
|
||||||
|
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (width-- > 0)
|
||||||
|
{
|
||||||
|
uint32 p = FETCH_G(palIndex);
|
||||||
|
p |= (FETCH_G(palIndex) << 8);
|
||||||
|
|
||||||
|
g += dgdx;
|
||||||
|
|
||||||
|
if (width-- > 0)
|
||||||
|
{
|
||||||
|
p |= (FETCH_G(palIndex) << 16);
|
||||||
|
p |= (FETCH_G(palIndex) << 24);
|
||||||
|
|
||||||
|
g += dgdx;
|
||||||
|
|
||||||
|
*(uint32*)pixel = p;
|
||||||
|
pixel += 2;
|
||||||
|
} else {
|
||||||
|
*(uint16*)pixel = p;
|
||||||
|
pixel += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x2 & 1)
|
||||||
|
{
|
||||||
|
*pixel = (*pixel & 0xFF00) | FETCH_G(palIndex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
INLINE void scanlineGT(uint16* buffer, int32 x1, int32 x2, uint32 g, uint32 t, int32 dgdx, uint32 dtdx) {
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
uint16* pixel = buffer + x1;
|
||||||
|
int32 width = (x2 - x1);
|
||||||
|
|
||||||
|
while (width--)
|
||||||
|
{
|
||||||
|
*pixel++ = FETCH_GT_PAL();
|
||||||
|
t += dtdx;
|
||||||
|
g += dgdx;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (x1 & 1)
|
||||||
|
{
|
||||||
|
uint16 &p = *(uint16*)((uint8*)buffer + x1 - 1);
|
||||||
|
p = (p & 0x00FF) | (FETCH_GT() << 8);
|
||||||
|
t += dtdx;
|
||||||
|
g += dgdx;
|
||||||
|
x1++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 width = (x2 - x1) >> 1;
|
||||||
|
uint16* pixel = (uint16*)((uint8*)buffer + x1);
|
||||||
|
|
||||||
|
dgdx <<= 1;
|
||||||
|
|
||||||
|
if (width && (x1 & 3))
|
||||||
|
{
|
||||||
|
uint16 p = FETCH_GT();
|
||||||
|
t += dtdx;
|
||||||
|
*pixel++ = p | (FETCH_GT() << 8);
|
||||||
|
t += dtdx;
|
||||||
|
|
||||||
|
g += dgdx;
|
||||||
|
|
||||||
|
width--;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (width-- > 0)
|
||||||
|
{
|
||||||
|
uint32 p = FETCH_GT();
|
||||||
|
t += dtdx;
|
||||||
|
p |= (FETCH_GT() << 8);
|
||||||
|
t += dtdx;
|
||||||
|
|
||||||
|
g += dgdx;
|
||||||
|
|
||||||
|
if (width-- > 0)
|
||||||
|
{
|
||||||
|
p |= (FETCH_GT() << 16);
|
||||||
|
t += dtdx;
|
||||||
|
p |= (FETCH_GT() << 24);
|
||||||
|
t += dtdx;
|
||||||
|
|
||||||
|
g += dgdx;
|
||||||
|
|
||||||
|
*(uint32*)pixel = p;
|
||||||
|
pixel += 2;
|
||||||
|
} else {
|
||||||
|
*(uint16*)pixel = p;
|
||||||
|
pixel += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x2 & 1)
|
||||||
|
{
|
||||||
|
*pixel = (*pixel & 0xFF00) | FETCH_GT();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void rasterizeG(uint16* buffer, int32 palIndex, Edge &L, Edge &R)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
while (L.h <= 0)
|
||||||
|
{
|
||||||
|
if (!L.nextG())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (R.h <= 0)
|
||||||
|
{
|
||||||
|
if (!R.nextG())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 h = MIN(L.h, R.h);
|
||||||
|
L.h -= h;
|
||||||
|
R.h -= h;
|
||||||
|
|
||||||
|
while (h--) {
|
||||||
|
int32 x1 = L.x >> 16;
|
||||||
|
int32 x2 = R.x >> 16;
|
||||||
|
|
||||||
|
if (x2 > x1)
|
||||||
|
{
|
||||||
|
int32 d = FixedInvU(x2 - x1);
|
||||||
|
|
||||||
|
int32 dgdx = d * ((R.g - L.g) >> 8) >> 16;
|
||||||
|
|
||||||
|
scanlineG(buffer, x1, x2, palIndex, L.g >> 8, dgdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += WIDTH / PIXEL_SIZE;
|
||||||
|
|
||||||
|
L.stepG();
|
||||||
|
R.stepG();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rasterizeGT(uint16* buffer, Edge &L, Edge &R)
|
||||||
|
{
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
while (L.h <= 0)
|
||||||
|
{
|
||||||
|
if (!L.nextGT())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (R.h <= 0)
|
||||||
|
{
|
||||||
|
if (!R.nextGT())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 h = MIN(L.h, R.h);
|
||||||
|
L.h -= h;
|
||||||
|
R.h -= h;
|
||||||
|
|
||||||
|
while (h--) {
|
||||||
|
int32 x1 = L.x >> 16;
|
||||||
|
int32 x2 = R.x >> 16;
|
||||||
|
|
||||||
|
if (x2 > x1)
|
||||||
|
{
|
||||||
|
uint32 d = FixedInvU(x2 - x1);
|
||||||
|
|
||||||
|
int32 dgdx = d * ((R.g - L.g) >> 8) >> 16;
|
||||||
|
|
||||||
|
uint32 u = d * ((R.t >> 16) - (L.t >> 16));
|
||||||
|
uint32 v = d * ((R.t & 0xFFFF) - (L.t & 0xFFFF));
|
||||||
|
uint32 dtdx = (u & 0xFFFF0000) | (v >> 16);
|
||||||
|
|
||||||
|
scanlineGT(buffer, x1, x2, L.g >> 8, L.t, dgdx, dtdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer += WIDTH / PIXEL_SIZE;
|
||||||
|
|
||||||
|
L.stepGT();
|
||||||
|
R.stepGT();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawTriangle(uint16 flags, int32 start, const int8* indices)
|
||||||
|
{
|
||||||
|
Vertex *v1, *v2, *v3;
|
||||||
|
|
||||||
|
bool clipped = indices[0] == indices[1];
|
||||||
|
|
||||||
|
if (clipped) {
|
||||||
|
v1 = gVertices + start;
|
||||||
|
v2 = v1 + 1;
|
||||||
|
v3 = v1 + 2;
|
||||||
|
} else {
|
||||||
|
v1 = gVertices + start;
|
||||||
|
v2 = v1 + indices[1];
|
||||||
|
v3 = v1 + indices[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 palIndex = flags & FACE_TEXTURE;
|
||||||
|
|
||||||
|
if (!(flags & FACE_COLORED)) {
|
||||||
|
const Texture &tex = textures[palIndex];
|
||||||
|
palIndex = 0xFFFF;
|
||||||
|
curTile = tiles[tex.tile];
|
||||||
|
if (!clipped) {
|
||||||
|
v1->u = tex.x0;
|
||||||
|
v1->v = tex.y0;
|
||||||
|
v2->u = tex.x1;
|
||||||
|
v2->v = tex.y1;
|
||||||
|
v3->u = tex.x2;
|
||||||
|
v3->v = tex.y2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortVertices(v1, v2, v3);
|
||||||
|
|
||||||
|
int32 temp = (v2->y - v1->y) * FixedInvU(v3->y - v1->y);
|
||||||
|
|
||||||
|
int32 longest = ((temp * (v3->x - v1->x)) >> 16) + (v1->x - v2->x);
|
||||||
|
if (longest == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge L, R;
|
||||||
|
|
||||||
|
if (longest < 0)
|
||||||
|
{
|
||||||
|
R.vert[0] = v3;
|
||||||
|
R.vert[1] = v2;
|
||||||
|
R.vert[2] = v1;
|
||||||
|
R.index = 2;
|
||||||
|
L.vert[0] = v3;
|
||||||
|
L.vert[1] = v1;
|
||||||
|
L.index = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
L.vert[0] = v3;
|
||||||
|
L.vert[1] = v2;
|
||||||
|
L.vert[2] = v1;
|
||||||
|
L.index = 2;
|
||||||
|
R.vert[0] = v3;
|
||||||
|
R.vert[1] = v1;
|
||||||
|
R.index = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (palIndex != 0xFFFF) {
|
||||||
|
rasterizeG((uint16*)fb + v1->y * (WIDTH / PIXEL_SIZE), palIndex, L, R);
|
||||||
|
} else {
|
||||||
|
rasterizeGT((uint16*)fb + v1->y * (WIDTH / PIXEL_SIZE), L, R);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawQuad(uint16 flags, int32 start, const int8* indices) {
|
||||||
|
Vertex *v1, *v2, *v3, *v4;
|
||||||
|
|
||||||
|
bool clipped = indices[0] == indices[1];
|
||||||
|
|
||||||
|
if (clipped) {
|
||||||
|
v1 = gVertices + start;
|
||||||
|
v2 = v1 + 1;
|
||||||
|
v3 = v1 + 2;
|
||||||
|
v4 = v1 + 3;
|
||||||
|
} else {
|
||||||
|
v1 = gVertices + start;
|
||||||
|
v2 = v1 + indices[1];
|
||||||
|
v3 = v1 + indices[2];
|
||||||
|
v4 = v1 + indices[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 palIndex = flags & FACE_TEXTURE;
|
||||||
|
|
||||||
|
if (!(flags & FACE_COLORED)) {
|
||||||
|
const Texture &tex = textures[palIndex];
|
||||||
|
palIndex = 0xFFFF;
|
||||||
|
curTile = tiles[tex.tile];
|
||||||
|
if (!clipped) {
|
||||||
|
v1->u = int32(tex.x0);
|
||||||
|
v1->v = int32(tex.y0);
|
||||||
|
v2->u = int32(tex.x1);
|
||||||
|
v2->v = int32(tex.y1);
|
||||||
|
v3->u = int32(tex.x2);
|
||||||
|
v3->v = int32(tex.y2);
|
||||||
|
v4->u = int32(tex.x3);
|
||||||
|
v4->v = int32(tex.y3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sortVertices(v1, v2, v3, v4);
|
||||||
|
|
||||||
|
int32 temp = (v2->y - v1->y) * FixedInvU(v4->y - v1->y);
|
||||||
|
|
||||||
|
int32 longest = ((temp * (v4->x - v1->x)) >> 16) + (v1->x - v2->x);
|
||||||
|
if (longest == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge L, R;
|
||||||
|
|
||||||
|
if (checkBackface(v1, v4, v2) == checkBackface(v1, v4, v3))
|
||||||
|
{
|
||||||
|
if (longest < 0)
|
||||||
|
{
|
||||||
|
L.vert[0] = v4;
|
||||||
|
L.vert[1] = v1;
|
||||||
|
L.index = 1;
|
||||||
|
R.vert[0] = v4;
|
||||||
|
R.vert[1] = v3;
|
||||||
|
R.vert[2] = v2;
|
||||||
|
R.vert[3] = v1;
|
||||||
|
R.index = 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
R.vert[0] = v4;
|
||||||
|
R.vert[1] = v1;
|
||||||
|
R.index = 1;
|
||||||
|
L.vert[0] = v4;
|
||||||
|
L.vert[1] = v3;
|
||||||
|
L.vert[2] = v2;
|
||||||
|
L.vert[3] = v1;
|
||||||
|
L.index = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
R.vert[0] = v4;
|
||||||
|
R.vert[1] = v3;
|
||||||
|
R.vert[2] = v1;
|
||||||
|
R.index = 2;
|
||||||
|
L.vert[0] = v4;
|
||||||
|
L.vert[1] = v2;
|
||||||
|
L.vert[2] = v1;
|
||||||
|
L.index = 2;
|
||||||
|
|
||||||
|
if (longest < 0)
|
||||||
|
{
|
||||||
|
swap(L.vert[1], R.vert[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (palIndex != 0xFFFF) {
|
||||||
|
rasterizeG((uint16*)fb + v1->y * (WIDTH / PIXEL_SIZE), palIndex, L, R);
|
||||||
|
} else {
|
||||||
|
rasterizeGT((uint16*)fb + v1->y * (WIDTH / PIXEL_SIZE), L, R);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawPoly(uint16 flags, int32 start, int32 count) {
|
||||||
|
uint16 palIndex = flags & FACE_TEXTURE;
|
||||||
|
|
||||||
|
if (!(flags & FACE_COLORED)) {
|
||||||
|
const Texture &tex = textures[palIndex];
|
||||||
|
palIndex = 0xFFFF;
|
||||||
|
curTile = tiles[tex.tile];
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 minY = 0x7FFF;
|
||||||
|
int32 maxY = -0x7FFF;
|
||||||
|
int32 t = start, b = start;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
Vertex *v = gVertices + start + i;
|
||||||
|
|
||||||
|
if (v->y < minY) {
|
||||||
|
minY = v->y;
|
||||||
|
t = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (v->y > maxY) {
|
||||||
|
maxY = v->y;
|
||||||
|
b = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge L, R;
|
||||||
|
L.vert[L.index = 0] = gVertices + start + b;
|
||||||
|
R.vert[R.index = 0] = gVertices + start + b;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
int32 idx = (b + count + i) % count;
|
||||||
|
|
||||||
|
L.vert[++L.index] = gVertices + start + idx;
|
||||||
|
|
||||||
|
if (idx == t) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
int32 idx = (b + count - i) % count;
|
||||||
|
|
||||||
|
R.vert[++R.index] = gVertices + start + idx;
|
||||||
|
|
||||||
|
if (idx == t) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex *v1 = gVertices + start + t;
|
||||||
|
|
||||||
|
if (palIndex != 0xFFFF) {
|
||||||
|
rasterizeG((uint16*)fb + v1->y * (WIDTH / PIXEL_SIZE), palIndex, L, R);
|
||||||
|
} else {
|
||||||
|
rasterizeGT((uint16*)fb + v1->y * (WIDTH / PIXEL_SIZE), L, R);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawGlyph(int32 index, int32 x, int32 y) {
|
||||||
|
const Sprite* sprite = sprites + spriteSequences[seqGlyphs].sStart + index;
|
||||||
|
|
||||||
|
int32 w = sprite->r - sprite->l;
|
||||||
|
int32 h = sprite->b - sprite->t;
|
||||||
|
|
||||||
|
w = (w >> 1) << 1; // make it even
|
||||||
|
|
||||||
|
int32 ix = x + sprite->l;
|
||||||
|
int32 iy = y + sprite->t;
|
||||||
|
|
||||||
|
uint16* ptr = (uint16*)fb + iy * (WIDTH / PIXEL_SIZE) + (ix >> 1);
|
||||||
|
|
||||||
|
const uint8* glyphData = tiles[sprite->tile] + 256 * sprite->v + sprite->u;
|
||||||
|
|
||||||
|
while (h--)
|
||||||
|
{
|
||||||
|
const uint8* p = glyphData;
|
||||||
|
|
||||||
|
for (int i = 0; i < (w / 2); i++) {
|
||||||
|
|
||||||
|
if (p[0] || p[1]) {
|
||||||
|
uint16 d = ptr[i];
|
||||||
|
|
||||||
|
if (p[0]) d = (d & 0xFF00) | p[0];
|
||||||
|
if (p[1]) d = (d & 0x00FF) | (p[1] << 8);
|
||||||
|
|
||||||
|
ptr[i] = d;
|
||||||
|
}
|
||||||
|
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += WIDTH / PIXEL_SIZE;
|
||||||
|
glyphData += 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void faceAddPolyClip(uint16 flags, Vertex** poly, int32 pCount)
|
||||||
|
{
|
||||||
|
#define LERP(a,b,t) (b + ((a - b) * t >> 16))
|
||||||
|
|
||||||
|
#define CLIP_AXIS(x, y, edge, output) {\
|
||||||
|
uint32 t = MyDiv((edge - b->x) << 16, a->x - b->x);\
|
||||||
|
Vertex* v = output + count++;\
|
||||||
|
v->x = edge;\
|
||||||
|
v->y = LERP(a->y, b->y, t);\
|
||||||
|
v->z = LERP(a->z, b->z, t);\
|
||||||
|
v->u = LERP(a->u, b->u, t);\
|
||||||
|
v->v = LERP(a->v, b->v, t);\
|
||||||
|
v->g = LERP(a->g, b->g, t);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CLIP_VERTEX(x, y, x0, x1, input, output) {\
|
||||||
|
const Vertex *a, *b = input[pCount - 1];\
|
||||||
|
for (int32 i = 0; i < pCount; i++) {\
|
||||||
|
a = b;\
|
||||||
|
b = input[i];\
|
||||||
|
if (a->x < x0) {\
|
||||||
|
if (b->x < x0) continue;\
|
||||||
|
CLIP_AXIS(x, y, x0, output);\
|
||||||
|
} else if (a->x > x1) {\
|
||||||
|
if (b->x > x1) continue;\
|
||||||
|
CLIP_AXIS(x, y, x1, output);\
|
||||||
|
}\
|
||||||
|
if (b->x < x0) {\
|
||||||
|
CLIP_AXIS(x, y, x0, output);\
|
||||||
|
} else if (b->x > x1) {\
|
||||||
|
CLIP_AXIS(x, y, x1, output);\
|
||||||
|
} else {\
|
||||||
|
output[count++] = *b;\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
if (count < 3) return;\
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(flags & FACE_COLORED)) {
|
||||||
|
const Texture &tex = textures[flags & FACE_TEXTURE];
|
||||||
|
curTile = tiles[tex.tile];
|
||||||
|
poly[0]->u = int32(tex.x0);
|
||||||
|
poly[0]->v = int32(tex.y0);
|
||||||
|
poly[1]->u = int32(tex.x1);
|
||||||
|
poly[1]->v = int32(tex.y1);
|
||||||
|
poly[2]->u = int32(tex.x2);
|
||||||
|
poly[2]->v = int32(tex.y2);
|
||||||
|
if (pCount == 4) {
|
||||||
|
poly[3]->u = int32(tex.x3);
|
||||||
|
poly[3]->v = int32(tex.y3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex tmp[8];
|
||||||
|
int32 count = 0;
|
||||||
|
|
||||||
|
// clip x
|
||||||
|
int32 x0 = clip.x0;
|
||||||
|
int32 x1 = clip.x1;
|
||||||
|
CLIP_VERTEX(x, y, x0, x1, poly, tmp);
|
||||||
|
|
||||||
|
pCount = count;
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
Vertex* output = gVertices + gVerticesCount;
|
||||||
|
|
||||||
|
// clip y
|
||||||
|
int32 y0 = clip.y0;
|
||||||
|
int32 y1 = clip.y1;
|
||||||
|
CLIP_VERTEX(y, x, y0, y1, &tmp, output);
|
||||||
|
|
||||||
|
Face &f = gFaces[gFacesCount++];
|
||||||
|
f.flags = flags;
|
||||||
|
f.start = gVerticesCount;
|
||||||
|
f.indices[0] = count;
|
||||||
|
f.indices[1] = count;
|
||||||
|
/*
|
||||||
|
if (count == 3) {
|
||||||
|
f.flags |= FACE_TRIANGLE;
|
||||||
|
f.depth = (output[0].z + output[1].z + output[2].z) / 3;
|
||||||
|
} else if (count == 4) {
|
||||||
|
f.depth = (output[0].z + output[1].z + output[2].z + output[3].z) >> 2;
|
||||||
|
} else*/ {
|
||||||
|
int32 depth = output[0].z;
|
||||||
|
for (int32 i = 1; i < count; i++) {
|
||||||
|
depth = (depth + output[i].z) >> 1;
|
||||||
|
}
|
||||||
|
f.depth = depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
gVerticesCount += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void faceAddQuad(uint16 flags, const Index* indices, int32 startVertex) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (gFacesCount >= MAX_FACES) {
|
||||||
|
DebugBreak();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Vertex* v1 = gVertices + startVertex + indices[0];
|
||||||
|
Vertex* v2 = gVertices + startVertex + indices[1];
|
||||||
|
Vertex* v3 = gVertices + startVertex + indices[2];
|
||||||
|
Vertex* v4 = gVertices + startVertex + indices[3];
|
||||||
|
|
||||||
|
if (v1->z < 0 || v2->z < 0 || v3->z < 0 || v4->z < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (checkBackface(v1, v2, v3))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (v1->clip & v2->clip & v3->clip & v4->clip)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (v1->clip | v2->clip | v3->clip | v4->clip) {
|
||||||
|
Vertex* poly[4] = { v1, v2, v3, v4 };
|
||||||
|
faceAddPolyClip(flags, poly, 4);
|
||||||
|
} else {
|
||||||
|
Face &f = gFaces[gFacesCount++];
|
||||||
|
f.flags = flags;
|
||||||
|
f.depth = (v1->z + v2->z + v3->z + v4->z) >> 2;
|
||||||
|
f.start = startVertex + indices[0];
|
||||||
|
f.indices[0] = 0;
|
||||||
|
f.indices[1] = indices[1] - indices[0];
|
||||||
|
f.indices[2] = indices[2] - indices[0];
|
||||||
|
f.indices[3] = indices[3] - indices[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void faceAddTriangle(uint16 flags, const Index* indices, int32 startVertex) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (gFacesCount >= MAX_FACES) {
|
||||||
|
DebugBreak();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
Vertex* v1 = gVertices + startVertex + indices[0];
|
||||||
|
Vertex* v2 = gVertices + startVertex + indices[1];
|
||||||
|
Vertex* v3 = gVertices + startVertex + indices[2];
|
||||||
|
|
||||||
|
if (v1->z < 0 || v2->z < 0 || v3->z < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (checkBackface(v1, v2, v3))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (v1->clip & v2->clip & v3->clip)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (v1->clip | v2->clip | v3->clip) {
|
||||||
|
Vertex* poly[3] = { v1, v2, v3 };
|
||||||
|
faceAddPolyClip(flags, poly, 3);
|
||||||
|
} else {
|
||||||
|
Face &f = gFaces[gFacesCount++];
|
||||||
|
f.flags = flags | FACE_TRIANGLE;
|
||||||
|
f.depth = (v1->z + v2->z + v3->z) / 3;
|
||||||
|
f.start = startVertex + indices[0];
|
||||||
|
f.indices[0] = 0;
|
||||||
|
f.indices[1] = indices[1] - indices[0];
|
||||||
|
f.indices[2] = indices[2] - indices[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int faceCmp(const void *a, const void *b) {
|
||||||
|
return ((Face*)b)->depth - ((Face*)a)->depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
//int32 gFacesCountMax, gVerticesCountMax;
|
||||||
|
|
||||||
|
void flush() {
|
||||||
|
if (gFacesCount) {
|
||||||
|
qsort(gFaces, gFacesCount, sizeof(Face), faceCmp);
|
||||||
|
|
||||||
|
//const uint16 mips[] = { 0xFFFF, 0xFEFE, 0xFCFC, 0xF8F8 };
|
||||||
|
|
||||||
|
for (int32 i = 0; i < gFacesCount; i++) {
|
||||||
|
const Face &f = gFaces[i];
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
//mipMask = mips[MIN(3, f.depth / 2048)];
|
||||||
|
|
||||||
|
if (f.flags & FACE_TRIANGLE) {
|
||||||
|
drawTriangle(f.flags, f.start, f.indices);
|
||||||
|
} else {
|
||||||
|
if (f.indices[0] == f.indices[1] /* && f.indices[0] > 4 */) {
|
||||||
|
drawPoly(f.flags, f.start, f.indices[0]);
|
||||||
|
} else {
|
||||||
|
drawQuad(f.flags, f.start, f.indices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (gFacesCount > gFacesCountMax) gFacesCountMax = gFacesCount;
|
||||||
|
//if (gVerticesCount > gVerticesCountMax) gVerticesCountMax = gVerticesCount;
|
||||||
|
//printf("%d %d\n", gFacesCountMax, gVerticesCountMax);
|
||||||
|
|
||||||
|
gVerticesCount = 0;
|
||||||
|
gFacesCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initRender() {
|
||||||
|
divTable[0] = 0;
|
||||||
|
for (uint32 i = 1; i < DIV_TABLE_SIZE; i++) {
|
||||||
|
divTable[i] = MyDiv(1 << 16, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
uint32* dst = (uint32*)fb;
|
||||||
|
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
uint32* end = dst + (WIDTH * HEIGHT >> 1);
|
||||||
|
#else
|
||||||
|
uint32* end = dst + (WIDTH * HEIGHT >> 2);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (dst < end) {
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
*dst++ = 0;
|
||||||
|
}
|
||||||
|
}
|
BIN
src/platform/gba/icon.png
Normal file
BIN
src/platform/gba/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 546 B |
595
src/platform/gba/main.cpp
Normal file
595
src/platform/gba/main.cpp
Normal file
@@ -0,0 +1,595 @@
|
|||||||
|
#ifndef _WIN32
|
||||||
|
#include <gba_console.h>
|
||||||
|
#include <gba_video.h>
|
||||||
|
#include <gba_timers.h>
|
||||||
|
#include <gba_interrupt.h>
|
||||||
|
#include <gba_systemcalls.h>
|
||||||
|
#include <gba_input.h>
|
||||||
|
#include <gba_dma.h>
|
||||||
|
#include <gba_affine.h>
|
||||||
|
#include <fade.h>
|
||||||
|
|
||||||
|
#include "LEVEL1_PHD.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
//#define PROFILE
|
||||||
|
|
||||||
|
#if defined(USE_MODE_5) || defined(_WIN32)
|
||||||
|
extern uint16 palette[256];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint8 lightmap[256 * 32];
|
||||||
|
|
||||||
|
extern Vertex gVertices[MAX_VERTICES];
|
||||||
|
extern uint32 gVerticesCount;
|
||||||
|
|
||||||
|
extern Face gFaces[MAX_FACES];
|
||||||
|
extern int32 gFacesCount;
|
||||||
|
|
||||||
|
extern Rect clip;
|
||||||
|
|
||||||
|
extern const uint8* tiles[15];
|
||||||
|
|
||||||
|
extern const uint8* curTile;
|
||||||
|
uint32 tilesCount;
|
||||||
|
|
||||||
|
extern int32 fps;
|
||||||
|
|
||||||
|
uint16 camRotY = 16 << 8;
|
||||||
|
|
||||||
|
extern int32 camSinY;
|
||||||
|
extern int32 camCosY;
|
||||||
|
|
||||||
|
extern int32 camX;
|
||||||
|
extern int32 camY;
|
||||||
|
extern int32 camZ;
|
||||||
|
|
||||||
|
extern uint16 roomsCount;
|
||||||
|
extern const Room* rooms;
|
||||||
|
|
||||||
|
extern uint32 texturesCount;
|
||||||
|
extern const Texture* textures;
|
||||||
|
|
||||||
|
extern const Sprite* sprites;
|
||||||
|
|
||||||
|
extern uint32 spriteSequencesCount;
|
||||||
|
extern const SpriteSequence* spriteSequences;
|
||||||
|
|
||||||
|
extern int32 seqGlyphs;
|
||||||
|
|
||||||
|
extern const uint8* meshData;
|
||||||
|
extern const uint32* meshOffsets;
|
||||||
|
|
||||||
|
extern const int32* nodes;
|
||||||
|
extern const Model* models;
|
||||||
|
|
||||||
|
extern void transform(int32 vx, int32 vy, int32 vz, int32 vg, int32 x, int32 y, int32 z);
|
||||||
|
extern void faceAddTriangle(uint16 flags, const Index* indices, int32 startVertex);
|
||||||
|
extern void faceAddQuad(uint16 flags, const Index* indices, int32 startVertex);
|
||||||
|
extern void flush();
|
||||||
|
extern void initRender();
|
||||||
|
|
||||||
|
void drawRoom(int16 roomIndex) {
|
||||||
|
const Room *room = rooms;
|
||||||
|
|
||||||
|
//Room::Portal *portals;
|
||||||
|
uint16 portalsCount;
|
||||||
|
|
||||||
|
//Room::Sector* sectors;
|
||||||
|
uint16 zSectors, xSectors;
|
||||||
|
|
||||||
|
//uint16 ambient;
|
||||||
|
|
||||||
|
//Room::Light* lights;
|
||||||
|
uint16 lightsCount;
|
||||||
|
|
||||||
|
//Room::Mesh* meshes;
|
||||||
|
uint16 meshesCount;
|
||||||
|
|
||||||
|
uint8 *ptr = (uint8*)room;
|
||||||
|
|
||||||
|
while (roomIndex--) {
|
||||||
|
uint32 dataSize;
|
||||||
|
memcpy(&dataSize, &room->dataSize, sizeof(dataSize));
|
||||||
|
ptr += sizeof(Room) + dataSize * 2;
|
||||||
|
|
||||||
|
portalsCount = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
//portals = (Room::Portal*)ptr;
|
||||||
|
ptr += sizeof(Room::Portal) * portalsCount;
|
||||||
|
|
||||||
|
zSectors = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
xSectors = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
//sectors = (Room::Sector*)sectors;
|
||||||
|
ptr += sizeof(Room::Sector) * zSectors * xSectors;
|
||||||
|
|
||||||
|
//ambient = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
|
||||||
|
lightsCount = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
//lights = (Room::Light*)ptr;
|
||||||
|
ptr += sizeof(Room::Light) * lightsCount;
|
||||||
|
|
||||||
|
meshesCount = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
//meshes = (Room::Mesh*)ptr;
|
||||||
|
ptr += sizeof(Room::Mesh) * meshesCount;
|
||||||
|
|
||||||
|
ptr += 2 + 2; // skip alternateRoom and flags
|
||||||
|
|
||||||
|
room = (Room*)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr += sizeof(Room);
|
||||||
|
|
||||||
|
uint16 vCount = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
Room::Vertex* vertices = (Room::Vertex*)ptr;
|
||||||
|
ptr += sizeof(Room::Vertex) * vCount;
|
||||||
|
|
||||||
|
// non-aligned data
|
||||||
|
int32 roomX;
|
||||||
|
int32 roomZ;
|
||||||
|
memcpy(&roomX, &room->info.x, sizeof(roomX));
|
||||||
|
memcpy(&roomZ, &room->info.z, sizeof(roomZ));
|
||||||
|
|
||||||
|
int32 dx = -camX + roomX;
|
||||||
|
int32 dy = -camY;
|
||||||
|
int32 dz = -camZ + roomZ;
|
||||||
|
|
||||||
|
int32 startVertex = gVerticesCount;
|
||||||
|
|
||||||
|
for (uint16 i = 0; i < vCount; i++) {
|
||||||
|
const Room::Vertex &v = vertices[i];
|
||||||
|
transform(v.x, v.y, v.z, v.lighting, dx, dy, dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 qCount = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
Quad* quads = (Quad*)ptr;
|
||||||
|
ptr += sizeof(Quad) * qCount;
|
||||||
|
|
||||||
|
for (uint16 i = 0; i < qCount; i++) {
|
||||||
|
faceAddQuad(quads[i].flags, quads[i].indices, startVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16 tCount = *((uint16*)ptr);
|
||||||
|
ptr += 2;
|
||||||
|
Triangle* triangles = (Triangle*)ptr;
|
||||||
|
ptr += sizeof(Triangle) * tCount;
|
||||||
|
|
||||||
|
for (uint16 i = 0; i < tCount; i++) {
|
||||||
|
faceAddTriangle(triangles[i].flags, triangles[i].indices, startVertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawMesh(int16 meshIndex, int32 x, int32 y, int32 z) {
|
||||||
|
uint32 offset = meshOffsets[meshIndex];
|
||||||
|
const uint8* ptr = meshData + offset;
|
||||||
|
|
||||||
|
//int16 cx = *(int16*)ptr; ptr += 2;
|
||||||
|
//int16 cy = *(int16*)ptr; ptr += 2;
|
||||||
|
//int16 cz = *(int16*)ptr; ptr += 2;
|
||||||
|
//int16 r = *(int16*)ptr; ptr += 2;
|
||||||
|
//ptr += 2; // skip flags
|
||||||
|
ptr += 2 * 5;
|
||||||
|
|
||||||
|
int16 vCount = *(int16*)ptr; ptr += 2;
|
||||||
|
const int16* vertices = (int16*)ptr;
|
||||||
|
ptr += vCount * 3 * sizeof(int16);
|
||||||
|
|
||||||
|
int16 nCount = *(int16*)ptr; ptr += 2;
|
||||||
|
//const int16* normals = (int16*)ptr;
|
||||||
|
if (nCount > 0) { // normals
|
||||||
|
ptr += nCount * 3 * sizeof(int16);
|
||||||
|
} else { // intensity
|
||||||
|
ptr += vCount * sizeof(int16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16 rCount = *(int16*)ptr; ptr += 2;
|
||||||
|
Quad* rFaces = (Quad*)ptr; ptr += rCount * sizeof(Quad);
|
||||||
|
|
||||||
|
int16 tCount = *(int16*)ptr; ptr += 2;
|
||||||
|
Triangle* tFaces = (Triangle*)ptr; ptr += tCount * sizeof(Triangle);
|
||||||
|
|
||||||
|
int16 crCount = *(int16*)ptr; ptr += 2;
|
||||||
|
Quad* crFaces = (Quad*)ptr; ptr += crCount * sizeof(Quad);
|
||||||
|
|
||||||
|
int16 ctCount = *(int16*)ptr; ptr += 2;
|
||||||
|
Triangle* ctFaces = (Triangle*)ptr; ptr += ctCount * sizeof(Triangle);
|
||||||
|
|
||||||
|
int32 startVertex = gVerticesCount;
|
||||||
|
|
||||||
|
int32 dx = x - camX;
|
||||||
|
int32 dy = y - camY;
|
||||||
|
int32 dz = z - camZ;
|
||||||
|
|
||||||
|
const int16* v = vertices;
|
||||||
|
for (uint16 i = 0; i < vCount; i++) {
|
||||||
|
transform(v[0], v[1], v[2], 4096, dx, dy, dz);
|
||||||
|
v += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < rCount; i++) {
|
||||||
|
faceAddQuad(rFaces[i].flags, rFaces[i].indices, startVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < crCount; i++) {
|
||||||
|
faceAddQuad(crFaces[i].flags | FACE_COLORED, crFaces[i].indices, startVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < tCount; i++) {
|
||||||
|
faceAddTriangle(tFaces[i].flags, tFaces[i].indices, startVertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < ctCount; i++) {
|
||||||
|
faceAddTriangle(ctFaces[i].flags | FACE_COLORED, ctFaces[i].indices, startVertex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawModel(int32 modelIndex, int32 x, int32 y, int32 z) {
|
||||||
|
const Model* model = models + modelIndex;
|
||||||
|
|
||||||
|
// non-aligned access
|
||||||
|
uint32 node, frame;
|
||||||
|
memcpy(&node, &model->node, sizeof(node));
|
||||||
|
memcpy(&frame, &model->frame, sizeof(frame));
|
||||||
|
|
||||||
|
Node bones[32];
|
||||||
|
memcpy(bones, nodes + node, (model->mCount - 1) * sizeof(Node));
|
||||||
|
|
||||||
|
const Node* n = bones;
|
||||||
|
|
||||||
|
struct StackItem {
|
||||||
|
int32 x, y, z;
|
||||||
|
} stack[4];
|
||||||
|
StackItem *s = stack;
|
||||||
|
|
||||||
|
drawMesh(model->mStart, x, y, z);
|
||||||
|
|
||||||
|
for (int i = 1; i < model->mCount; i++) {
|
||||||
|
if (n->flags & 1) {
|
||||||
|
s--;
|
||||||
|
x = s->x;
|
||||||
|
y = s->y;
|
||||||
|
z = s->z;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n->flags & 2) {
|
||||||
|
s->x = x;
|
||||||
|
s->y = y;
|
||||||
|
s->z = z;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
x += n->x;
|
||||||
|
y += n->y;
|
||||||
|
z += n->z;
|
||||||
|
n++;
|
||||||
|
|
||||||
|
drawMesh(model->mStart + i, x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readLevel(const uint8 *data) {
|
||||||
|
tilesCount = *((uint32*)(data + 4));
|
||||||
|
for (uint32 i = 0; i < tilesCount; i++) {
|
||||||
|
tiles[i] = data + 8 + 256 * 256 * i;
|
||||||
|
}
|
||||||
|
|
||||||
|
roomsCount = *((uint16*)(data + 720908));
|
||||||
|
rooms = (Room*)(data + 720908 + 2);
|
||||||
|
|
||||||
|
texturesCount = *((uint32*)(data + 1271686));
|
||||||
|
textures = (Texture*)(data + 1271686 + 4);
|
||||||
|
|
||||||
|
sprites = (Sprite*)(data + 1289634);
|
||||||
|
|
||||||
|
spriteSequencesCount = *((uint32*)(data + 1292130));
|
||||||
|
spriteSequences = (SpriteSequence*)(data + 1292130 + 4);
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < spriteSequencesCount; i++) {
|
||||||
|
if (spriteSequences[i].type == 190) {
|
||||||
|
seqGlyphs = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
meshData = data + 908172 + 4;
|
||||||
|
meshOffsets = (uint32*)(data + 975724 + 4);
|
||||||
|
|
||||||
|
nodes = (int32*)(data + 990318);
|
||||||
|
|
||||||
|
models = (Model*)(data + 1270670);
|
||||||
|
|
||||||
|
const uint8* f_lightmap = data + 1320576;
|
||||||
|
memcpy(lightmap, f_lightmap, sizeof(lightmap));
|
||||||
|
|
||||||
|
#if !(defined(USE_MODE_5) || defined(_WIN32))
|
||||||
|
uint16 palette[256];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const uint8* f_palette = data + 1328768;
|
||||||
|
|
||||||
|
const uint8* p = f_palette;
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++) {
|
||||||
|
palette[i] = (p[0] >> 1) | ((p[1] >> 1) << 5) | ((p[2] >> 1) << 10);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
palette[1] = RGB8(0, 255, 0);
|
||||||
|
|
||||||
|
#ifndef USE_MODE_5
|
||||||
|
SetPalette(palette);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define CAM_SPEED (1 << 3)
|
||||||
|
#define CAM_ROT_SPEED (1 << 3)
|
||||||
|
#else
|
||||||
|
#define CAM_SPEED (1 << 6)
|
||||||
|
#define CAM_ROT_SPEED (1 << 8)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void updateCamera() {
|
||||||
|
if (keys[IK_LEFT]) camRotY -= CAM_ROT_SPEED;
|
||||||
|
if (keys[IK_RIGHT]) camRotY += CAM_ROT_SPEED;
|
||||||
|
|
||||||
|
{
|
||||||
|
ALIGN4 ObjAffineSource src;
|
||||||
|
ALIGN4 ObjAffineDest dst;
|
||||||
|
|
||||||
|
src.sX = 0x0100;
|
||||||
|
src.sY = 0x0100;
|
||||||
|
src.theta = camRotY;
|
||||||
|
|
||||||
|
ObjAffineSet(&src, &dst, 1, 2);
|
||||||
|
|
||||||
|
camCosY = dst.pd << 8;
|
||||||
|
camSinY = dst.pc << 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 dx = camSinY;
|
||||||
|
int32 dz = camCosY;
|
||||||
|
|
||||||
|
dx *= CAM_SPEED;
|
||||||
|
dz *= CAM_SPEED;
|
||||||
|
|
||||||
|
dx >>= 16;
|
||||||
|
dz >>= 16;
|
||||||
|
|
||||||
|
if (keys[IK_UP]) {
|
||||||
|
camX += int32(dx);
|
||||||
|
camZ += int32(dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys[IK_DOWN]) {
|
||||||
|
camX -= int32(dx);
|
||||||
|
camZ -= int32(dz);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys[IK_L]) {
|
||||||
|
camX -= int32(dz);
|
||||||
|
camZ += int32(dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys[IK_R]) {
|
||||||
|
camX += int32(dz);
|
||||||
|
camZ -= int32(dx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keys[IK_A]) camY -= CAM_SPEED;
|
||||||
|
if (keys[IK_B]) camY += CAM_SPEED;
|
||||||
|
|
||||||
|
clip = { 0, 0, FRAME_WIDTH, FRAME_HEIGHT };
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawNumber(int32 number, int32 x, int32 y) {
|
||||||
|
const int32 widths[] = { 12, 8, 10, 10, 10, 10, 10, 10, 10, 10 };
|
||||||
|
|
||||||
|
while (number > 0) {
|
||||||
|
x -= widths[number % 10];
|
||||||
|
drawGlyph(52 + (number % 10), x, y);
|
||||||
|
number /= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(int32 frames) {
|
||||||
|
for (int32 i = 0; i < frames; i++) {
|
||||||
|
updateCamera();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void render() {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
drawRoom(6);
|
||||||
|
flush();
|
||||||
|
|
||||||
|
drawRoom(0);
|
||||||
|
drawModel(0, 75162, 3072 - 512, 5000 + 1024);
|
||||||
|
flush();
|
||||||
|
|
||||||
|
drawNumber(fps, WIDTH, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
HDC hDC;
|
||||||
|
|
||||||
|
void VBlankIntrWait() {
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
for (int i = 0; i < WIDTH * HEIGHT; i++) {
|
||||||
|
uint16 c = fb[i];
|
||||||
|
VRAM[i] = (((c << 3) & 0xFF) << 16) | ((((c >> 5) << 3) & 0xFF) << 8) | ((c >> 10 << 3) & 0xFF) | 0xFF000000;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
for (int i = 0; i < WIDTH * HEIGHT; i++) {
|
||||||
|
uint16 c = palette[fb[i]];
|
||||||
|
VRAM[i] = (((c << 3) & 0xFF) << 16) | ((((c >> 5) << 3) & 0xFF) << 8) | ((c >> 10 << 3) & 0xFF) | 0xFF000000;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const BITMAPINFO bmi = { sizeof(BITMAPINFOHEADER), WIDTH, -HEIGHT, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
|
||||||
|
StretchDIBits(hDC, 0, 0, 240 * WND_SCALE, 160 * WND_SCALE, 0, 0, WIDTH, HEIGHT, VRAM, &bmi, DIB_RGB_COLORS, SRCCOPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||||
|
switch (msg) {
|
||||||
|
case WM_DESTROY :
|
||||||
|
PostQuitMessage(0);
|
||||||
|
break;
|
||||||
|
case WM_KEYDOWN :
|
||||||
|
case WM_KEYUP : {
|
||||||
|
InputKey key = IK_MAX;
|
||||||
|
switch (wParam) {
|
||||||
|
case VK_UP : key = IK_UP; break;
|
||||||
|
case VK_RIGHT : key = IK_RIGHT; break;
|
||||||
|
case VK_DOWN : key = IK_DOWN; break;
|
||||||
|
case VK_LEFT : key = IK_LEFT; break;
|
||||||
|
case 'Z' : key = IK_A; break;
|
||||||
|
case 'X' : key = IK_B; break;
|
||||||
|
case 'A' : key = IK_L; break;
|
||||||
|
case 'S' : key = IK_R; break;
|
||||||
|
}
|
||||||
|
if (key != IK_MAX) {
|
||||||
|
keys[key] = msg != WM_KEYUP;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default :
|
||||||
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32 frameIndex = 0;
|
||||||
|
int32 fpsCounter = 0;
|
||||||
|
|
||||||
|
void vblank() {
|
||||||
|
frameIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
{
|
||||||
|
FILE *f = fopen("C:/Projects/TR/TR1_ANDROID/LEVEL1.PHD", "rb");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
int32 size = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET);
|
||||||
|
LEVEL1_PHD = new uint8[size];
|
||||||
|
fread(LEVEL1_PHD, 1, size, f);
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// set low latency mode via WAITCNT register (thanks to GValiente)
|
||||||
|
#define BIT_SET(y, flag) (y |= (flag))
|
||||||
|
#define REG_WAITCNT_NV *(u16*)(REG_BASE + 0x0204)
|
||||||
|
|
||||||
|
BIT_SET(REG_WAITCNT_NV, 0x0008 | 0x0010 | 0x4000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
initRender();
|
||||||
|
|
||||||
|
readLevel(LEVEL1_PHD);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
RECT r = { 0, 0, 240 * WND_SCALE, 160 * WND_SCALE };
|
||||||
|
|
||||||
|
AdjustWindowRect(&r, WS_OVERLAPPEDWINDOW, false);
|
||||||
|
int wx = (GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2;
|
||||||
|
int wy = (GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2;
|
||||||
|
|
||||||
|
HWND hWnd = CreateWindow("static", "OpenLara GBA", WS_OVERLAPPEDWINDOW, wx + r.left, wy + r.top, r.right - r.left, r.bottom - r.top, 0, 0, 0, 0);
|
||||||
|
hDC = GetDC(hWnd);
|
||||||
|
|
||||||
|
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)&wndProc);
|
||||||
|
ShowWindow(hWnd, SW_SHOWDEFAULT);
|
||||||
|
|
||||||
|
MSG msg;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
update(1);
|
||||||
|
render();
|
||||||
|
|
||||||
|
VBlankIntrWait();
|
||||||
|
}
|
||||||
|
} while (msg.message != WM_QUIT);
|
||||||
|
|
||||||
|
#else
|
||||||
|
irqInit();
|
||||||
|
irqSet(IRQ_VBLANK, vblank);
|
||||||
|
irqEnable(IRQ_VBLANK);
|
||||||
|
|
||||||
|
uint16 mode = BG2_ON | BACKBUFFER;
|
||||||
|
|
||||||
|
#ifdef USE_MODE_5
|
||||||
|
mode |= MODE_5;
|
||||||
|
|
||||||
|
REG_BG2PA = 256 - 64 - 16 - 4 - 1;
|
||||||
|
REG_BG2PD = 256 - 48 - 2;
|
||||||
|
#else
|
||||||
|
mode |= MODE_4;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int32 lastFrameIndex = -1;
|
||||||
|
|
||||||
|
#ifdef PROFILE
|
||||||
|
int counter = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
//VBlankIntrWait();
|
||||||
|
|
||||||
|
#ifdef PROFILE
|
||||||
|
if (counter++ >= 10) return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SetMode(mode ^= BACKBUFFER);
|
||||||
|
fb ^= 0xA000;
|
||||||
|
|
||||||
|
scanKeys();
|
||||||
|
uint16 key = keysDown() | keysHeld();
|
||||||
|
keys[IK_UP] = (key & KEY_UP);
|
||||||
|
keys[IK_RIGHT] = (key & KEY_RIGHT);
|
||||||
|
keys[IK_DOWN] = (key & KEY_DOWN);
|
||||||
|
keys[IK_LEFT] = (key & KEY_LEFT);
|
||||||
|
keys[IK_A] = (key & KEY_A);
|
||||||
|
keys[IK_B] = (key & KEY_B);
|
||||||
|
keys[IK_L] = (key & KEY_L);
|
||||||
|
keys[IK_R] = (key & KEY_R);
|
||||||
|
|
||||||
|
int32 frame = frameIndex;
|
||||||
|
update(frame - lastFrameIndex);
|
||||||
|
lastFrameIndex = frame;
|
||||||
|
|
||||||
|
render();
|
||||||
|
|
||||||
|
fpsCounter++;
|
||||||
|
if (frameIndex >= 60) {
|
||||||
|
frameIndex -= 60;
|
||||||
|
lastFrameIndex -= 60;
|
||||||
|
|
||||||
|
fps = fpsCounter;
|
||||||
|
|
||||||
|
fpsCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
1
src/platform/gba/profile.bat
Normal file
1
src/platform/gba/profile.bat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
NO$GBA C:\Projects\OpenLara\src\platform\gba\OpenLara.elf
|
51
src/platform/gba/sdiv32.s
Normal file
51
src/platform/gba/sdiv32.s
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
@--------------------------------------------------------------------------------
|
||||||
|
@ udiv.s
|
||||||
|
@--------------------------------------------------------------------------------
|
||||||
|
@ Provides an implementation of signed division
|
||||||
|
@--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ refer to the unsigned division
|
||||||
|
.extern __aeabi_uidivmod
|
||||||
|
.extern __aeabi_uidiv
|
||||||
|
|
||||||
|
@ r0: the numerator / r1: the denominator
|
||||||
|
@ after it, r0 has the quotient and r1 has the modulo
|
||||||
|
.section .iwram, "ax", %progbits
|
||||||
|
.align 2
|
||||||
|
.arm
|
||||||
|
.global __aeabi_idivmod
|
||||||
|
.type __aeabi_idivmod STT_FUNC
|
||||||
|
__aeabi_idivmod:
|
||||||
|
|
||||||
|
.section .iwram, "ax", %progbits
|
||||||
|
.align 2
|
||||||
|
.arm
|
||||||
|
.global __aeabi_idiv
|
||||||
|
.type __aeabi_idiv STT_FUNC
|
||||||
|
__aeabi_idiv:
|
||||||
|
|
||||||
|
@ Move the lr to r12 and make the numbers positive
|
||||||
|
mov r12, lr
|
||||||
|
|
||||||
|
cmp r0, #0
|
||||||
|
rsblt r0, #0
|
||||||
|
orrlt r12, #1 << 30
|
||||||
|
|
||||||
|
cmp r1, #0
|
||||||
|
rsblt r1, #0
|
||||||
|
orrlt r12, #1 << 31
|
||||||
|
|
||||||
|
@ Call the unsigned division
|
||||||
|
.extern udiv32pastzero
|
||||||
|
bl udiv32pastzero
|
||||||
|
|
||||||
|
@ Test the old sign bits
|
||||||
|
tst r12, #1 << 30
|
||||||
|
rsbne r0, r0, #0
|
||||||
|
rsbne r1, r0, #0
|
||||||
|
tst r12, #1 << 31
|
||||||
|
rsbne r0, r0, #0
|
||||||
|
|
||||||
|
@ Erase the sign bits from the return address, and return
|
||||||
|
bic r12, #3 << 30
|
||||||
|
bx r12
|
79
src/platform/gba/udiv32.s
Normal file
79
src/platform/gba/udiv32.s
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
@--------------------------------------------------------------------------------
|
||||||
|
@ udiv.s
|
||||||
|
@--------------------------------------------------------------------------------
|
||||||
|
@ Provides an implementation of unsigned division
|
||||||
|
@--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ Source code taken from https://www.chiark.greenend.org.uk/~theom/riscos/docs/ultimate/a252div.txt
|
||||||
|
@ r0: the numerator / r1: the denominator
|
||||||
|
@ after it, r0 has the quotient and r1 has the modulo
|
||||||
|
.section .iwram, "ax", %progbits
|
||||||
|
.align 2
|
||||||
|
.arm
|
||||||
|
.global __aeabi_uidivmod
|
||||||
|
.type __aeabi_uidivmod STT_FUNC
|
||||||
|
__aeabi_uidivmod:
|
||||||
|
|
||||||
|
.section .iwram, "ax", %progbits
|
||||||
|
.align 2
|
||||||
|
.arm
|
||||||
|
.global __aeabi_uidiv
|
||||||
|
.type __aeabi_uidiv STT_FUNC
|
||||||
|
__aeabi_uidiv:
|
||||||
|
|
||||||
|
@ Check for division by zero
|
||||||
|
cmp r1, #0
|
||||||
|
bxeq lr
|
||||||
|
|
||||||
|
.global udiv32pastzero
|
||||||
|
udiv32pastzero:
|
||||||
|
@ If n < d, just bail out as well
|
||||||
|
cmp r0, r1 @ n, d
|
||||||
|
movlo r1, r0 @ mod = n
|
||||||
|
movlo r0, #0 @ quot = 0
|
||||||
|
bxlo lr
|
||||||
|
|
||||||
|
@ Move the denominator to r2 and start to build a counter that
|
||||||
|
@ counts the difference on the number of bits on each numerator
|
||||||
|
@ and denominator
|
||||||
|
@ From now on: r0 = quot/num, r1 = mod, r2 = denom, r3 = counter
|
||||||
|
mov r2, r1
|
||||||
|
mov r3, #28 @ first guess on difference
|
||||||
|
mov r1, r0, lsr #4 @ r1 = num >> 4
|
||||||
|
|
||||||
|
@ Iterate three times to get the counter up to 4-bit precision
|
||||||
|
cmp r2, r1, lsr #12
|
||||||
|
suble r3, r3, #16
|
||||||
|
movle r1, r1, lsr #16
|
||||||
|
|
||||||
|
cmp r2, r1, lsr #4
|
||||||
|
suble r3, r3, #8
|
||||||
|
movle r1, r1, lsr #8
|
||||||
|
|
||||||
|
cmp r2, r1
|
||||||
|
suble r3, r3, #4
|
||||||
|
movle r1, r1, lsr #4
|
||||||
|
|
||||||
|
@ shift the numerator by the counter and flip the sign of the denom
|
||||||
|
mov r0, r0, lsl r3
|
||||||
|
adds r0, r0, r0
|
||||||
|
rsb r2, r2, #0
|
||||||
|
|
||||||
|
@ dynamically jump to the exact copy of the iteration
|
||||||
|
add r3, r3, r3, lsl #1 @ counter *= 3
|
||||||
|
add pc, pc, r3, lsl #2 @ jump
|
||||||
|
mov r0, r0 @ pipelining issues
|
||||||
|
|
||||||
|
@ here, r0 = num << (r3 + 1), r1 = num >> (32-r3), r2 = -denom
|
||||||
|
@ now, the real iteration part
|
||||||
|
.global divIteration
|
||||||
|
divIteration:
|
||||||
|
.rept 32
|
||||||
|
adcs r1, r2, r1, lsl #1
|
||||||
|
sublo r1, r1, r2
|
||||||
|
adcs r0, r0, r0
|
||||||
|
.endr
|
||||||
|
|
||||||
|
@ and then finally quit
|
||||||
|
@ r0 = quotient, r1 = remainder
|
||||||
|
bx lr
|
Reference in New Issue
Block a user