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