Compare commits
20 Commits
Author | SHA1 | Date |
---|---|---|
duarteapcoelho | ca63ef88ea | |
duarteapcoelho | f18108eaee | |
duarteapcoelho | df09c12c07 | |
duarteapcoelho | 3f1ea2cc5d | |
duarteapcoelho | 98f79eeb05 | |
duarteapcoelho | 332771104f | |
duarteapcoelho | 136e536544 | |
duarteapcoelho | 003955e423 | |
duarteapcoelho | aefbb3cc50 | |
duarteapcoelho | 113ea0366a | |
duarteapcoelho | 7aaaace43b | |
duarteapcoelho | b1951208ae | |
duarteapcoelho | 96c4b8bdcf | |
duarteapcoelho | 9749f08077 | |
duarteapcoelho | 0b11ffac4c | |
duarteapcoelho | 9877547fe1 | |
Duarte Coelho | a70d716564 | |
duarteapcoelho | ed3503bb5b | |
duarteapcoelho | ac2dc37cb2 | |
duarteapcoelho | 53c148d369 |
|
@ -4,5 +4,10 @@ prizm/*
|
|||
sdl/*
|
||||
!sdl/Makefile
|
||||
|
||||
gint/*
|
||||
!gint/Makefile
|
||||
|
||||
resources/models/models.h
|
||||
resources/models/models.blend1
|
||||
|
||||
release
|
||||
|
|
35
Makefile
35
Makefile
|
@ -1,15 +1,44 @@
|
|||
all: sdl prizm
|
||||
SOURCES = $(wildcard src/*)
|
||||
|
||||
all: sdl prizm gint
|
||||
|
||||
sdl: sdl/racing
|
||||
|
||||
prizm: prizm/racing.g3a
|
||||
|
||||
gint: gint/racing_singleplayer.g3a
|
||||
|
||||
clean:
|
||||
make $(MFLAGS) -C sdl/ clean
|
||||
make $(MFLAGS) -C prizm/ clean
|
||||
make $(MFLAGS) -C gint/ clean
|
||||
|
||||
sdl/racing:
|
||||
sdl/racing: $(SOURCES)
|
||||
make $(MFLAGS) -C sdl/
|
||||
|
||||
prizm/racing.g3a:
|
||||
prizm/racing.g3a: $(SOURCES)
|
||||
make $(MFLAGS) -C prizm/
|
||||
|
||||
gint/racing_singleplayer.g3a: $(SOURCES)
|
||||
make $(MFLAGS) -C gint/
|
||||
|
||||
package: release/racing.zip release/racing.tar.gz release/racing_singleplayer.zip release/racing_singleplayer.tar.gz
|
||||
|
||||
release/racing.zip: prizm/racing.g3a
|
||||
mkdir -p release
|
||||
zip -j release/racing.zip LICENSE prizm/racing.g3a
|
||||
|
||||
release/racing.tar.gz: prizm/racing.g3a
|
||||
mkdir -p release
|
||||
tar czvf release/racing.tar.gz LICENSE -C prizm racing.g3a
|
||||
|
||||
release/racing_singleplayer.zip: gint/racing_singleplayer.g3a
|
||||
mkdir -p release
|
||||
zip -j release/racing_singleplayer.zip LICENSE gint/racing_singleplayer.g3a
|
||||
|
||||
release/racing_singleplayer.tar.gz: gint/racing_singleplayer.g3a
|
||||
mkdir -p release
|
||||
tar czvf release/racing_singleplayer.tar.gz LICENSE -C gint racing_singleplayer.g3a
|
||||
|
||||
package-clean:
|
||||
rm release -rf
|
||||
|
|
37
README.md
37
README.md
|
@ -3,12 +3,12 @@ A 3D, multiplayer racing game for casio fx-CG50 calculators
|
|||
|
||||
## Pictures
|
||||
![Picture 1](resources/picture1.png)
|
||||
![Picture 2](resources/picture2.jpg)
|
||||
![Video](resources/video.gif)
|
||||
|
||||
## Features
|
||||
- 3D graphics
|
||||
- Simple multiplayer (just connect two calculators)
|
||||
- Runs at 14 FPS normally and 21 FPS overclocked, on the fx-CG50.
|
||||
- The multiplayer version runs at about 14 FPS and the singleplayer version runs at 24 FPS
|
||||
|
||||
## Controls
|
||||
- Press `up`/`8` to accelerate and `down`/`5` to brake
|
||||
|
@ -17,41 +17,48 @@ A 3D, multiplayer racing game for casio fx-CG50 calculators
|
|||
- If you return from the menu, press any key to continue playing
|
||||
- **Tip**: if you use `left` and `right` to turn and `8` to accelerate, you can turn while accelerating
|
||||
|
||||
## How to install
|
||||
- Download the zip file from the releases page and extract it to get the `.g3a` file.
|
||||
- Connect the calculator via USB and choose the `USB Flash` option (`F1`)
|
||||
- Copy the file to the calculator.
|
||||
|
||||
## Notes/Bugs
|
||||
- In multiplayer, each player sees the other car behind where it really is, so it's possible that both players see themselves finish first.
|
||||
- For multiplayer to work, both calculators must be running at the same frequency (if you overclock one, you must overclock both).
|
||||
- The car's movement isn't totally independent from framerate, so it may be a bit more or less slippery if you're overclocking or underclocking.
|
||||
- The car's movement isn't totally independent from framerate, so it may be a bit more or less slippery if you're overclocking, underclocking, or using another calculator.
|
||||
- This game also works on casio fx-CG20 calculators, but it's too slow (at least without overclocking).
|
||||
- Running this game might cause file transfer to stop working. To fix this, reset the calculator by pressing the button on the back or removing and re-inserting a battery. This doesn't delete any files.
|
||||
- If you connect the cable while one calculator is in the menu, it might start trying to receive data. To avoid this, only connect the cable while the game is running on both calculators).
|
||||
- If you connect the cable while one calculator is in the menu, it might start trying to receive files. To avoid this, only connect the cable while the game is running on both calculators.
|
||||
|
||||
## How to build
|
||||
### Linux
|
||||
- Either set up the Prizm SDK ([PrizmSDK Setup Guide](https://prizm.cemetech.net/index.php/PrizmSDK_Setup_Guide))
|
||||
### prizm sdk version (with multiplayer)
|
||||
This version supports multiplayer, but it's slower than the gint version.
|
||||
#### Linux
|
||||
- Set up the Prizm SDK ([PrizmSDK Setup Guide](https://prizm.cemetech.net/index.php/PrizmSDK_Setup_Guide))
|
||||
- Set the FXCGSDK environment variable to where you installed libfxcg (`export FXCGSDK=...`), or put the prizm_racing directory in `libfxcg/projects/prizm_racing`.
|
||||
- Run `make prizm`
|
||||
- If you want to compile the SDL version (used for testing), install sdl2 and sdl2-ttf and run `make sdl`. The binary will be in `sdl/racing`, but it must be run from the prizm_racing directory (with `sdl/racing`)
|
||||
|
||||
### Windows
|
||||
#### Windows (pirzm sdk version)
|
||||
- Download the Prizm SDK ([https://github.com/Jonimoose/libfxcg/releases](https://github.com/Jonimoose/libfxcg/releases))
|
||||
- Make sure the path to the SDK doesn't contain any spaces
|
||||
- Put the `prizm_racing` directory in `PrizmSDK/projects/prizm_racing`
|
||||
- Run `..\..\bin\make.exe prizm`
|
||||
|
||||
### gint version (singleplayer only)
|
||||
This version doesn't support multiplayer, but it runs faster and doesn't have a border.
|
||||
#### Linux
|
||||
- Install gint ([https://gitea.planet-casio.com/Lephenixnoir/gint](https://gitea.planet-casio.com/Lephenixnoir/gint))
|
||||
- Install libprof ([https://gitea.planet-casio.com/Lephenixnoir/libprof](https://gitea.planet-casio.com/Lephenixnoir/libprof))
|
||||
- Run `make gint`
|
||||
|
||||
## Technical information
|
||||
### 3D rendering
|
||||
- All the rendering code is in `src/rasterizer.h` and `src/rasterizer.cpp`
|
||||
- Every triangle is clipped to avoid drawing triangles outside the screen. If a triangle is only partially inside the screen, it's cut in one or two triangles. This doesn't happen with the cones and the car to improve performance.
|
||||
- The triangles are rasterized using the scan line algorithm with a depth buffer.
|
||||
- The triangles are split into two (one with a flat top and another with a flat bottom) and rasterized.
|
||||
- This renderer only supports diffuse directional lighting, because this way there is only one color per triangle, which increases performance.
|
||||
- Because the calculator doesn't have a floating point unit (FPU), everything related to rendering uses fixed point numbers (defined in src/fp.h). This caused some issues related to precision, most of which were solved by checking where the floating point calculations were overflowing.
|
||||
- To improve performance, the cones that are too far away from the camera are replaced with a simpler model and the ones even further away aren't drawn at all.
|
||||
|
||||
#### Potential rendering performance improvements
|
||||
- Use DMA to clear the screen
|
||||
- Draw the grass without using the 3D renderer (maybe using DMA)
|
||||
- Clip models before clipping triangles
|
||||
|
||||
### Multiplayer
|
||||
All of the multiplayer code is in `src/main.cpp`
|
||||
- When the game starts, a second car is created outside the track.
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
CC = sh-elf-g++
|
||||
CFLAGS += -Wall -Wextra -Ofast -funroll-loops -DGINT
|
||||
CFLAGS += -DFXCG50 -DTARGET_FXCG50 -m4-nofpu -mb -ffreestanding -nostdlib -fstrict-volatile-bitfields
|
||||
LDFLAGS = -m4-nofpu -mb -nostdlib -Wl,--no-warn-rwx-segments -T fxcg50.ld -lgint-cg -lc -lgcc -lgint-cg -lprof-cg
|
||||
|
||||
INCLUDES =
|
||||
|
||||
SRCDIR = ../src
|
||||
|
||||
SOURCES = $(wildcard $(SRCDIR)/*.cpp)
|
||||
OBJECTS = $(patsubst $(SRCDIR)/%,%,$(SOURCES:.cpp=.o))
|
||||
DEPS = $(patsubst $(SRCDIR)/%,%,$(SOURCES:.cpp=.d))
|
||||
|
||||
racing_singleplayer.g3a: racing.bin
|
||||
mkg3a racing.bin racing_singleplayer.g3a -n basic:racing_singleplayer -i uns:../resources/icons/unselected.bmp -i sel:../resources/icons/selected.bmp
|
||||
|
||||
racing.bin: racing
|
||||
sh-elf-objcopy -O binary -R .bss -R .gint_bss racing racing.bin
|
||||
|
||||
racing: $(OBJECTS)
|
||||
@echo "Linking..."
|
||||
$(CC) $^ -o racing $(LDFLAGS)
|
||||
|
||||
%.o: $(SRCDIR)/%.cpp
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c -o $@ -MMD $< -MF "$(patsubst $(SRCDIR)/%,%,$(<:.cpp=.d))"
|
||||
|
||||
clean:
|
||||
rm racing_singleplayer.g3a racing.bin racing $(OBJECTS) $(DEPS) -f
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
-include $(DEPS)
|
|
@ -5,7 +5,7 @@ file = open(os.path.dirname(__file__) + "/../../src/models.h", "w")
|
|||
file.truncate(0)
|
||||
for object in bpy.data.objects:
|
||||
if object.type == 'MESH':
|
||||
file.write("Triangle " + object.name + "_triangles[" + str(len(object.data.polygons)) + "] = {\n")
|
||||
file.write("#ifdef GINT\nstatic\n#endif\nTriangle " + object.name + "_triangles[" + str(len(object.data.polygons)) + "] = {\n")
|
||||
for polygon in object.data.polygons:
|
||||
file.write("\t{\n")
|
||||
for vertex in polygon.vertices:
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 340 KiB |
Binary file not shown.
After Width: | Height: | Size: 12 MiB |
|
@ -0,0 +1,36 @@
|
|||
#ifdef GINT
|
||||
#include "display.h"
|
||||
Color newColor(int r, int g, int b){
|
||||
return {
|
||||
.r = r,
|
||||
.g = g,
|
||||
.b = b,
|
||||
.color = ((r & 0b11111000)<<8) + ((g & 0b11111100)<<3)+(b>>3),
|
||||
};
|
||||
}
|
||||
|
||||
namespace Display {
|
||||
int textHeight = 0;
|
||||
|
||||
void init(){
|
||||
dsize("a", NULL, NULL, &textHeight);
|
||||
}
|
||||
|
||||
void clear(Color color){
|
||||
dclear(color.color);
|
||||
}
|
||||
void destroy(){}
|
||||
int textWidth(const char *text){
|
||||
int w;
|
||||
dsize(text, NULL, &w, NULL);
|
||||
return w;
|
||||
}
|
||||
void drawText(int x, int y, const char *text, Color color){
|
||||
dtext(x, y, color.color, text);
|
||||
}
|
||||
|
||||
void show() {
|
||||
dupdate();
|
||||
}
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
#include <gint/display.h>
|
||||
|
||||
#define DISPLAY_WIDTH DWIDTH
|
||||
#define DISPLAY_HEIGHT DHEIGHT
|
||||
|
||||
struct Color {
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
color_t color;
|
||||
};
|
||||
|
||||
namespace Display {
|
||||
inline void fillRect(int x, int y, int w, int h, Color color){
|
||||
color_t *s = (color_t*)gint_vram;
|
||||
s+=(y*DISPLAY_WIDTH)+x;
|
||||
while(h--){
|
||||
unsigned w2=w;
|
||||
while(w2--)
|
||||
*s++=color.color;
|
||||
s+=DISPLAY_WIDTH-w;
|
||||
}
|
||||
}
|
||||
inline void drawPoint(int x, int y, Color color){
|
||||
gint_vram[DISPLAY_WIDTH*y + x] = color.color;
|
||||
}
|
||||
};
|
|
@ -1,7 +1,6 @@
|
|||
#ifdef PRIZM
|
||||
#include "display.h"
|
||||
#include "util.h"
|
||||
#include <fxcg/display.h>
|
||||
|
||||
Color newColor(int r, int g, int b){
|
||||
return {
|
||||
|
@ -21,8 +20,9 @@ namespace Display {
|
|||
}
|
||||
|
||||
void clear(Color color){
|
||||
for(unsigned short *s = VRAMAddress; s < VRAMAddress + DISPLAY_WIDTH*DISPLAY_HEIGHT; s++){
|
||||
*s = color.color;
|
||||
long v = color.color | (color.color << (8*sizeof(unsigned short)));
|
||||
for(int i = 0; i < DISPLAY_WIDTH*DISPLAY_HEIGHT/2; i++){
|
||||
((long*)VRAMAddress)[i] = v;
|
||||
}
|
||||
}
|
||||
void destroy(){}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#include <fxcg/display.h>
|
||||
|
||||
#define DISPLAY_WIDTH LCD_WIDTH_PX
|
||||
#define DISPLAY_HEIGHT LCD_HEIGHT_PX
|
||||
|
||||
struct Color {
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
unsigned short color;
|
||||
};
|
||||
|
||||
namespace Display {
|
||||
extern unsigned short *VRAMAddress;
|
||||
inline void fillRect(int x, int y, int w, int h, Color color){
|
||||
unsigned short*s=VRAMAddress;
|
||||
s+=(y*384)+x;
|
||||
while(h--){
|
||||
unsigned w2=w;
|
||||
while(w2--)
|
||||
*s++=color.color;
|
||||
s+=384-w;
|
||||
}
|
||||
}
|
||||
inline void drawPoint(int x, int y, Color color){
|
||||
*(VRAMAddress + x + y * DISPLAY_WIDTH) = color.color;
|
||||
}
|
||||
};
|
|
@ -1,7 +1,5 @@
|
|||
#ifdef SDL
|
||||
#include "display.h"
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#define DISPLAY_WIDTH 384
|
||||
#define DISPLAY_HEIGHT 216
|
||||
|
||||
struct Color {
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
};
|
||||
|
||||
extern SDL_Renderer *renderer;
|
||||
|
||||
namespace Display {
|
||||
inline void fillRect(int x, int y, int w, int h, Color color){
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
|
||||
SDL_Rect rect;
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.w = w;
|
||||
rect.h = h;
|
||||
SDL_RenderFillRect(renderer, &rect);
|
||||
}
|
||||
inline void drawPoint(int x, int y, Color color){
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
|
||||
SDL_RenderDrawPoint(renderer, x, y);
|
||||
}
|
||||
};
|
|
@ -1 +0,0 @@
|
|||
#include "display.h"
|
|
@ -1,38 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef PRIZM
|
||||
#include <fxcg/display.h>
|
||||
#ifdef GINT
|
||||
#include "display-gint.h"
|
||||
#endif
|
||||
|
||||
#define DISPLAY_WIDTH LCD_WIDTH_PX
|
||||
#define DISPLAY_HEIGHT LCD_HEIGHT_PX
|
||||
#ifdef PRIZM
|
||||
#include "display-prizm.h"
|
||||
#endif
|
||||
|
||||
#ifdef CE
|
||||
#include "display-ce.h"
|
||||
#endif
|
||||
|
||||
#ifdef SDL
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
|
||||
#define DISPLAY_WIDTH 384
|
||||
#define DISPLAY_HEIGHT 216
|
||||
extern SDL_Renderer *renderer;
|
||||
#include "display-sdl.h"
|
||||
#endif
|
||||
|
||||
struct Color {
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
#ifdef PRIZM
|
||||
unsigned short color;
|
||||
bool operator != (Color o){
|
||||
return color != o.color;
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL
|
||||
bool operator != (Color o){
|
||||
return r != o.r || g != o.g || b != o.b;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
Color newColor(int r, int g, int b);
|
||||
|
||||
namespace Display {
|
||||
|
@ -43,36 +26,4 @@ namespace Display {
|
|||
void clear(Color color);
|
||||
int textWidth(const char *text);
|
||||
void drawText(int x, int y, const char *text, Color color);
|
||||
|
||||
#ifdef PRIZM
|
||||
extern unsigned short *VRAMAddress;
|
||||
inline void fillRect(int x, int y, int w, int h, Color color){
|
||||
unsigned short*s=VRAMAddress;
|
||||
s+=(y*384)+x;
|
||||
while(h--){
|
||||
unsigned w2=w;
|
||||
while(w2--)
|
||||
*s++=color.color;
|
||||
s+=384-w;
|
||||
}
|
||||
}
|
||||
inline void drawPoint(int x, int y, Color color){
|
||||
*(VRAMAddress + x + y * DISPLAY_WIDTH) = color.color;
|
||||
}
|
||||
#endif
|
||||
#ifdef SDL
|
||||
inline void fillRect(int x, int y, int w, int h, Color color){
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
|
||||
SDL_Rect rect;
|
||||
rect.x = x;
|
||||
rect.y = y;
|
||||
rect.w = w;
|
||||
rect.h = h;
|
||||
SDL_RenderFillRect(renderer, &rect);
|
||||
}
|
||||
inline void drawPoint(int x, int y, Color color){
|
||||
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255);
|
||||
SDL_RenderDrawPoint(renderer, x, y);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#ifdef GINT
|
||||
#include "input.h"
|
||||
#include "util.h"
|
||||
#include <gint/drivers/keydev.h>
|
||||
uint8_t keyState[12];
|
||||
uint8_t lastKeyState[12];
|
||||
namespace Input {
|
||||
bool keyDown(int key){
|
||||
int row = (key >> 4);
|
||||
int col = 0x80 >> (key & 0x7);
|
||||
|
||||
return (keyState[row] & col) != 0;
|
||||
}
|
||||
bool keyDownLast(int key){
|
||||
int row = (key >> 4);
|
||||
int col = 0x80 >> (key & 0x7);
|
||||
|
||||
return (lastKeyState[row] & col) != 0;
|
||||
}
|
||||
|
||||
void init(){
|
||||
}
|
||||
|
||||
void _updateKeys(){
|
||||
while(pollevent().type != KEYEV_NONE);
|
||||
memcpy(lastKeyState, keyState, sizeof(uint8_t)*12);
|
||||
memcpy(keyState, keydev_std()->state_now, sizeof(uint8_t)*12);
|
||||
}
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,61 @@
|
|||
#include <gint/keycodes.h>
|
||||
|
||||
#define KEY_MENU KEY_MENU
|
||||
#define KEY_EXIT KEY_EXIT
|
||||
#define KEY_EXE KEY_EXE
|
||||
#define KEY_AC KEY_ACON
|
||||
#define KEY_DEL KEY_DEL
|
||||
#define KEY_OPTN KEY_OPTN
|
||||
#define KEY_VARS KEY_VARS
|
||||
|
||||
#define KEY_0 KEY_0
|
||||
#define KEY_1 KEY_1
|
||||
#define KEY_2 KEY_2
|
||||
#define KEY_3 KEY_3
|
||||
#define KEY_4 KEY_4
|
||||
#define KEY_5 KEY_5
|
||||
#define KEY_6 KEY_6
|
||||
#define KEY_7 KEY_7
|
||||
#define KEY_8 KEY_8
|
||||
#define KEY_9 KEY_9
|
||||
|
||||
#define KEY_A -1
|
||||
#define KEY_B -1
|
||||
#define KEY_C -1
|
||||
#define KEY_D -1
|
||||
#define KEY_E -1
|
||||
#define KEY_F -1
|
||||
#define KEY_G -1
|
||||
#define KEY_H -1
|
||||
#define KEY_I -1
|
||||
#define KEY_J -1
|
||||
#define KEY_K -1
|
||||
#define KEY_L -1
|
||||
#define KEY_M -1
|
||||
#define KEY_N -1
|
||||
#define KEY_O -1
|
||||
#define KEY_P -1
|
||||
#define KEY_Q -1
|
||||
#define KEY_R -1
|
||||
#define KEY_S -1
|
||||
#define KEY_T -1
|
||||
#define KEY_U -1
|
||||
#define KEY_V -1
|
||||
#define KEY_W -1
|
||||
#define KEY_X -1
|
||||
#define KEY_Y -1
|
||||
#define KEY_Z -1
|
||||
|
||||
#define KEY_F1 KEY_F1
|
||||
#define KEY_F2 KEY_F2
|
||||
#define KEY_F3 KEY_F3
|
||||
#define KEY_F4 KEY_F4
|
||||
#define KEY_F5 KEY_F5
|
||||
#define KEY_F6 KEY_F6
|
||||
|
||||
#define KEY_UP KEY_UP
|
||||
#define KEY_DOWN KEY_DOWN
|
||||
#define KEY_LEFT KEY_LEFT
|
||||
#define KEY_RIGHT KEY_RIGHT
|
||||
|
||||
#define KEY_SHIFT KEY_SHIFT
|
|
@ -2,6 +2,7 @@
|
|||
#include "input.h"
|
||||
#include "util.h"
|
||||
|
||||
#define keyboard_register ((unsigned short*)0xA44B0000)
|
||||
unsigned short lastkey[8] = {0,0,0,0,0,0,0,0};
|
||||
unsigned short holdkey[8] = {0,0,0,0,0,0,0,0};
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
#include <fxcg/keyboard.h>
|
||||
|
||||
#define KEY_MENU KEY_PRGM_MENU
|
||||
#define KEY_EXIT KEY_PRGM_EXIT
|
||||
#define KEY_EXE 31
|
||||
#define KEY_AC 10
|
||||
#define KEY_DEL 44
|
||||
#define KEY_OPTN 68
|
||||
#define KEY_VARS 58
|
||||
|
||||
#define KEY_0 KEY_PRGM_0
|
||||
#define KEY_1 KEY_PRGM_1
|
||||
#define KEY_2 KEY_PRGM_2
|
||||
#define KEY_3 KEY_PRGM_3
|
||||
#define KEY_4 KEY_PRGM_4
|
||||
#define KEY_5 KEY_PRGM_5
|
||||
#define KEY_6 KEY_PRGM_6
|
||||
#define KEY_7 KEY_PRGM_7
|
||||
#define KEY_8 KEY_PRGM_8
|
||||
#define KEY_9 KEY_PRGM_9
|
||||
|
||||
#define KEY_A 76
|
||||
#define KEY_B 66
|
||||
#define KEY_C 56
|
||||
#define KEY_D 46
|
||||
#define KEY_E 36
|
||||
#define KEY_F 26
|
||||
#define KEY_G 75
|
||||
#define KEY_H 65
|
||||
#define KEY_I 55
|
||||
#define KEY_J 45
|
||||
#define KEY_K 35
|
||||
#define KEY_L 25
|
||||
#define KEY_M 74
|
||||
#define KEY_N 64
|
||||
#define KEY_O 54
|
||||
#define KEY_P 73
|
||||
#define KEY_Q 63
|
||||
#define KEY_R 53
|
||||
#define KEY_S 43
|
||||
#define KEY_T 33
|
||||
#define KEY_U 72
|
||||
#define KEY_V 62
|
||||
#define KEY_W 52
|
||||
#define KEY_X 42
|
||||
#define KEY_Y 32
|
||||
#define KEY_Z 71
|
||||
|
||||
#define KEY_F1 79
|
||||
#define KEY_F2 69
|
||||
#define KEY_F3 59
|
||||
#define KEY_F4 49
|
||||
#define KEY_F5 39
|
||||
#define KEY_F6 29
|
||||
|
||||
#define KEY_UP KEY_PRGM_UP
|
||||
#define KEY_DOWN KEY_PRGM_DOWN
|
||||
#define KEY_LEFT KEY_PRGM_LEFT
|
||||
#define KEY_RIGHT KEY_PRGM_RIGHT
|
||||
|
||||
#define KEY_SHIFT 78
|
|
@ -0,0 +1,61 @@
|
|||
#include <SDL2/SDL.h>
|
||||
|
||||
#define KEY_MENU SDL_SCANCODE_TAB
|
||||
#define KEY_EXIT SDL_SCANCODE_ESCAPE
|
||||
#define KEY_EXE SDL_SCANCODE_SPACE
|
||||
#define KEY_AC SDL_SCANCODE_BACKSPACE
|
||||
#define KEY_DEL SDL_SCANCODE_DELETE
|
||||
#define KEY_OPTN SDL_SCANCODE_BACKSPACE
|
||||
#define KEY_VARS SDL_SCANCODE_BACKSPACE
|
||||
|
||||
#define KEY_0 SDL_SCANCODE_0
|
||||
#define KEY_1 SDL_SCANCODE_1
|
||||
#define KEY_2 SDL_SCANCODE_2
|
||||
#define KEY_3 SDL_SCANCODE_3
|
||||
#define KEY_4 SDL_SCANCODE_4
|
||||
#define KEY_5 SDL_SCANCODE_5
|
||||
#define KEY_6 SDL_SCANCODE_6
|
||||
#define KEY_7 SDL_SCANCODE_7
|
||||
#define KEY_8 SDL_SCANCODE_8
|
||||
#define KEY_9 SDL_SCANCODE_9
|
||||
|
||||
#define KEY_A SDL_SCANCODE_A
|
||||
#define KEY_B SDL_SCANCODE_B
|
||||
#define KEY_C SDL_SCANCODE_C
|
||||
#define KEY_D SDL_SCANCODE_D
|
||||
#define KEY_E SDL_SCANCODE_E
|
||||
#define KEY_F SDL_SCANCODE_F
|
||||
#define KEY_G SDL_SCANCODE_G
|
||||
#define KEY_H SDL_SCANCODE_H
|
||||
#define KEY_I SDL_SCANCODE_I
|
||||
#define KEY_J SDL_SCANCODE_J
|
||||
#define KEY_K SDL_SCANCODE_K
|
||||
#define KEY_L SDL_SCANCODE_L
|
||||
#define KEY_M SDL_SCANCODE_M
|
||||
#define KEY_N SDL_SCANCODE_N
|
||||
#define KEY_O SDL_SCANCODE_O
|
||||
#define KEY_P SDL_SCANCODE_P
|
||||
#define KEY_Q SDL_SCANCODE_Q
|
||||
#define KEY_R SDL_SCANCODE_R
|
||||
#define KEY_S SDL_SCANCODE_S
|
||||
#define KEY_T SDL_SCANCODE_T
|
||||
#define KEY_U SDL_SCANCODE_U
|
||||
#define KEY_V SDL_SCANCODE_V
|
||||
#define KEY_W SDL_SCANCODE_W
|
||||
#define KEY_X SDL_SCANCODE_X
|
||||
#define KEY_Y SDL_SCANCODE_Y
|
||||
#define KEY_Z SDL_SCANCODE_Z
|
||||
|
||||
#define KEY_F1 SDL_SCANCODE_F1
|
||||
#define KEY_F2 SDL_SCANCODE_F2
|
||||
#define KEY_F3 SDL_SCANCODE_F3
|
||||
#define KEY_F4 SDL_SCANCODE_F4
|
||||
#define KEY_F5 SDL_SCANCODE_F5
|
||||
#define KEY_F6 SDL_SCANCODE_F6
|
||||
|
||||
#define KEY_UP SDL_SCANCODE_UP
|
||||
#define KEY_DOWN SDL_SCANCODE_DOWN
|
||||
#define KEY_LEFT SDL_SCANCODE_LEFT
|
||||
#define KEY_RIGHT SDL_SCANCODE_RIGHT
|
||||
|
||||
#define KEY_SHIFT SDL_SCANCODE_LSHIFT
|
132
src/input.h
132
src/input.h
|
@ -1,133 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef GINT
|
||||
#include "input-gint.h"
|
||||
#endif
|
||||
|
||||
#ifdef PRIZM
|
||||
#include <fxcg/keyboard.h>
|
||||
#include "input-prizm.h"
|
||||
#endif
|
||||
|
||||
#define KEY_MENU KEY_PRGM_MENU
|
||||
#define KEY_EXIT KEY_PRGM_EXIT
|
||||
#define KEY_EXE 31
|
||||
#define KEY_AC 10
|
||||
#define KEY_DEL 44
|
||||
#define KEY_OPTN 68
|
||||
#define KEY_VARS 58
|
||||
|
||||
#define KEY_0 KEY_PRGM_0
|
||||
#define KEY_1 KEY_PRGM_1
|
||||
#define KEY_2 KEY_PRGM_2
|
||||
#define KEY_3 KEY_PRGM_3
|
||||
#define KEY_4 KEY_PRGM_4
|
||||
#define KEY_5 KEY_PRGM_5
|
||||
#define KEY_6 KEY_PRGM_6
|
||||
#define KEY_7 KEY_PRGM_7
|
||||
#define KEY_8 KEY_PRGM_8
|
||||
#define KEY_9 KEY_PRGM_9
|
||||
|
||||
#define KEY_A 76
|
||||
#define KEY_B 66
|
||||
#define KEY_C 56
|
||||
#define KEY_D 46
|
||||
#define KEY_E 36
|
||||
#define KEY_F 26
|
||||
#define KEY_G 75
|
||||
#define KEY_H 65
|
||||
#define KEY_I 55
|
||||
#define KEY_J 45
|
||||
#define KEY_K 35
|
||||
#define KEY_L 25
|
||||
#define KEY_M 74
|
||||
#define KEY_N 64
|
||||
#define KEY_O 54
|
||||
#define KEY_P 73
|
||||
#define KEY_Q 63
|
||||
#define KEY_R 53
|
||||
#define KEY_S 43
|
||||
#define KEY_T 33
|
||||
#define KEY_U 72
|
||||
#define KEY_V 62
|
||||
#define KEY_W 52
|
||||
#define KEY_X 42
|
||||
#define KEY_Y 32
|
||||
#define KEY_Z 71
|
||||
|
||||
#define KEY_F1 79
|
||||
#define KEY_F2 69
|
||||
#define KEY_F3 59
|
||||
#define KEY_F4 49
|
||||
#define KEY_F5 39
|
||||
#define KEY_F6 29
|
||||
|
||||
#define KEY_UP KEY_PRGM_UP
|
||||
#define KEY_DOWN KEY_PRGM_DOWN
|
||||
#define KEY_LEFT KEY_PRGM_LEFT
|
||||
#define KEY_RIGHT KEY_PRGM_RIGHT
|
||||
|
||||
#define KEY_SHIFT 78
|
||||
|
||||
#define keyboard_register ((unsigned short*)0xA44B0000)
|
||||
#ifdef CE
|
||||
#include "input-ce.h"
|
||||
#endif
|
||||
|
||||
#ifdef SDL
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#define KEY_MENU SDL_SCANCODE_TAB
|
||||
#define KEY_EXIT SDL_SCANCODE_ESCAPE
|
||||
#define KEY_EXE SDL_SCANCODE_SPACE
|
||||
#define KEY_AC SDL_SCANCODE_BACKSPACE
|
||||
#define KEY_DEL SDL_SCANCODE_DELETE
|
||||
#define KEY_OPTN SDL_SCANCODE_BACKSPACE
|
||||
#define KEY_VARS SDL_SCANCODE_BACKSPACE
|
||||
|
||||
#define KEY_0 SDL_SCANCODE_0
|
||||
#define KEY_1 SDL_SCANCODE_1
|
||||
#define KEY_2 SDL_SCANCODE_2
|
||||
#define KEY_3 SDL_SCANCODE_3
|
||||
#define KEY_4 SDL_SCANCODE_4
|
||||
#define KEY_5 SDL_SCANCODE_5
|
||||
#define KEY_6 SDL_SCANCODE_6
|
||||
#define KEY_7 SDL_SCANCODE_7
|
||||
#define KEY_8 SDL_SCANCODE_8
|
||||
#define KEY_9 SDL_SCANCODE_9
|
||||
|
||||
#define KEY_A SDL_SCANCODE_A
|
||||
#define KEY_B SDL_SCANCODE_B
|
||||
#define KEY_C SDL_SCANCODE_C
|
||||
#define KEY_D SDL_SCANCODE_D
|
||||
#define KEY_E SDL_SCANCODE_E
|
||||
#define KEY_F SDL_SCANCODE_F
|
||||
#define KEY_G SDL_SCANCODE_G
|
||||
#define KEY_H SDL_SCANCODE_H
|
||||
#define KEY_I SDL_SCANCODE_I
|
||||
#define KEY_J SDL_SCANCODE_J
|
||||
#define KEY_K SDL_SCANCODE_K
|
||||
#define KEY_L SDL_SCANCODE_L
|
||||
#define KEY_M SDL_SCANCODE_M
|
||||
#define KEY_N SDL_SCANCODE_N
|
||||
#define KEY_O SDL_SCANCODE_O
|
||||
#define KEY_P SDL_SCANCODE_P
|
||||
#define KEY_Q SDL_SCANCODE_Q
|
||||
#define KEY_R SDL_SCANCODE_R
|
||||
#define KEY_S SDL_SCANCODE_S
|
||||
#define KEY_T SDL_SCANCODE_T
|
||||
#define KEY_U SDL_SCANCODE_U
|
||||
#define KEY_V SDL_SCANCODE_V
|
||||
#define KEY_W SDL_SCANCODE_W
|
||||
#define KEY_X SDL_SCANCODE_X
|
||||
#define KEY_Y SDL_SCANCODE_Y
|
||||
#define KEY_Z SDL_SCANCODE_Z
|
||||
|
||||
#define KEY_F1 SDL_SCANCODE_F1
|
||||
#define KEY_F2 SDL_SCANCODE_F2
|
||||
#define KEY_F3 SDL_SCANCODE_F3
|
||||
#define KEY_F4 SDL_SCANCODE_F4
|
||||
#define KEY_F5 SDL_SCANCODE_F5
|
||||
#define KEY_F6 SDL_SCANCODE_F6
|
||||
|
||||
#define KEY_UP SDL_SCANCODE_UP
|
||||
#define KEY_DOWN SDL_SCANCODE_DOWN
|
||||
#define KEY_LEFT SDL_SCANCODE_LEFT
|
||||
#define KEY_RIGHT SDL_SCANCODE_RIGHT
|
||||
|
||||
#define KEY_SHIFT SDL_SCANCODE_LSHIFT
|
||||
#include "input-sdl.h"
|
||||
#endif
|
||||
|
||||
namespace Input {
|
||||
|
|
121
src/main.cpp
121
src/main.cpp
|
@ -10,6 +10,12 @@
|
|||
#include "car.h"
|
||||
#include "track.h"
|
||||
|
||||
#ifdef GINT
|
||||
#include <gint/gint.h>
|
||||
#include <gint/mmu.h>
|
||||
#include <gint/dma.h>
|
||||
#endif
|
||||
|
||||
#ifdef PRIZM
|
||||
#include <fxcg/system.h>
|
||||
#include <fxcg/serial.h>
|
||||
|
@ -21,12 +27,19 @@ vec3<float> cameraPos = {0, 0, 0};
|
|||
vec3<float> cameraSpeed = {0, 0, 0};
|
||||
float cameraAngle = 0;
|
||||
|
||||
int main(){
|
||||
fp st[SIN_SAMPLES];
|
||||
sinTable = st;
|
||||
createSinTable();
|
||||
|
||||
#ifdef GINT
|
||||
static GALIGNED(32) unsigned char depthBuffer[RENDER_WIDTH*RENDER_HEIGHT];
|
||||
#include "models.h"
|
||||
#endif
|
||||
|
||||
int main(){
|
||||
#ifndef GINT
|
||||
unsigned char depthBuffer[RENDER_WIDTH*RENDER_HEIGHT];
|
||||
#include "models.h"
|
||||
#endif
|
||||
Rasterizer::depthBuffer = depthBuffer;
|
||||
|
||||
createSinTable();
|
||||
|
||||
Triangle simpleConeTriangles[] = {
|
||||
{
|
||||
|
@ -49,51 +62,31 @@ int main(){
|
|||
Track::coneMesh = {22, cone_triangles};
|
||||
Track::simpleConeMesh = {2, simpleConeTriangles};
|
||||
|
||||
Time::init();
|
||||
|
||||
Display::init();
|
||||
Display::clear(newColor(0, 0, 0));
|
||||
Display::clear(newColor(70, 180, 220));
|
||||
Display::show();
|
||||
|
||||
Time::update();
|
||||
|
||||
Input::init();
|
||||
|
||||
fp depthBuffer[RENDER_WIDTH*RENDER_HEIGHT];
|
||||
Rasterizer::depthBuffer = depthBuffer;
|
||||
|
||||
srand(0);
|
||||
|
||||
Triangle floorTriangles[2] = {
|
||||
{
|
||||
{-400, 0, -400},
|
||||
{-400, 0, 400},
|
||||
{400, 0, -400},
|
||||
{0, -1, 0},
|
||||
newColor(32, 79, 19)
|
||||
},
|
||||
{
|
||||
{-400, 0, 400},
|
||||
{400, 0, 400},
|
||||
{400, 0, -400},
|
||||
{0, -1, 0},
|
||||
newColor(32, 79, 19)
|
||||
},
|
||||
};
|
||||
|
||||
Model floor({2, floorTriangles});
|
||||
|
||||
Triangle sunTriangles[2] = {
|
||||
{
|
||||
{-1, -1, 0},
|
||||
{-1, 1, 0},
|
||||
{1, -1, 0},
|
||||
{0, 1, 0},
|
||||
{0, 0, -1},
|
||||
newColor(255, 255, 0)
|
||||
},
|
||||
{
|
||||
{-1, 1, 0},
|
||||
{1, 1, 0},
|
||||
{1, -1, 0},
|
||||
{0, 1, 0},
|
||||
{0, 0, -1},
|
||||
newColor(255, 255, 0)
|
||||
},
|
||||
};
|
||||
|
@ -140,10 +133,13 @@ int main(){
|
|||
Rasterizer::setFOV(70);
|
||||
|
||||
Car car = Car();
|
||||
#ifdef PRIZM
|
||||
Car enemyCar = Car();
|
||||
enemyCar.position = {-1000, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef PRIZM
|
||||
Serial_Close(1);
|
||||
while(Serial_IsOpen() != 1){
|
||||
unsigned char mode[6] = {0, 5, 0, 0, 0, 0}; // 9600 bps 8n1
|
||||
Serial_Open(mode);
|
||||
|
@ -190,9 +186,15 @@ int main(){
|
|||
#endif
|
||||
|
||||
if(Input::keyPressed(KEY_MENU)){
|
||||
#ifdef GINT
|
||||
gint_osmenu();
|
||||
#endif
|
||||
#ifdef PRIZM
|
||||
while(Input::keyDown(KEY_MENU))
|
||||
Input::update();
|
||||
|
||||
Serial_Close(1);
|
||||
|
||||
timer = Timer_Install(0, []() {
|
||||
Keyboard_PutKeycode(4, 9, 0);
|
||||
Timer_Stop(timer);
|
||||
|
@ -203,12 +205,22 @@ int main(){
|
|||
Bdisp_EnableColor(1);
|
||||
GetKey(&k);
|
||||
|
||||
Time::update();
|
||||
Serial_Close(1);
|
||||
while(Serial_IsOpen() != 1){
|
||||
unsigned char mode[6] = {0, 5, 0, 0, 0, 0}; // 9600 bps 8n1
|
||||
Serial_Open(mode);
|
||||
}
|
||||
Serial_ClearTX();
|
||||
Serial_ClearRX();
|
||||
|
||||
continue;
|
||||
#endif
|
||||
#ifdef SDL
|
||||
return 0;
|
||||
#endif
|
||||
int t = Time::delta;
|
||||
Time::update();
|
||||
Time::delta = t;
|
||||
}
|
||||
|
||||
car.processInput();
|
||||
|
@ -226,14 +238,38 @@ int main(){
|
|||
cameraSpeed = ls;
|
||||
}
|
||||
|
||||
Display::clear(newColor(70, 180, 220));
|
||||
|
||||
view = mat4();
|
||||
view = mat4::rotateX(view, HALF_PI*0.1);
|
||||
view = mat4::translate(view, 0, 2, 6);
|
||||
view = mat4::rotateY(view, -cameraAngle - HALF_PI);
|
||||
view = mat4::translate(view, -cameraPos.x, 0, -cameraPos.z);
|
||||
|
||||
int floorY = fp_tan(-HALF_PI*0.1) / Rasterizer::fov_d * fp(DISPLAY_WIDTH) + fp(DISPLAY_HEIGHT/2);
|
||||
#ifdef PRIZM
|
||||
long v1 = newColor(70, 180, 220).color | (newColor(70, 180, 220).color << (8*sizeof(unsigned short)));
|
||||
long v2 = newColor(32, 79, 19).color | (newColor(32, 79, 19).color << (8*sizeof(unsigned short)));
|
||||
for(int i = 0; i < floorY*DISPLAY_WIDTH/2; i++){
|
||||
((long*)Display::VRAMAddress)[i] = v1;
|
||||
}
|
||||
for(int i = floorY*DISPLAY_WIDTH/2; i < DISPLAY_WIDTH*DISPLAY_HEIGHT/2; i++){
|
||||
((long*)Display::VRAMAddress)[i] = v2;
|
||||
}
|
||||
#else
|
||||
#ifdef GINT
|
||||
uint16_t sky = newColor(70, 180, 220).color;
|
||||
uint16_t grass = newColor(32, 79, 10).color;
|
||||
int minY = floorY - (floorY%4);
|
||||
int maxY = floorY + (4 - (floorY%4));
|
||||
dma_memset(gint_vram, (sky << 16) | sky, DISPLAY_WIDTH*minY*2);
|
||||
Display::fillRect(0, minY, DISPLAY_WIDTH, floorY-minY, newColor(70, 180, 220));
|
||||
Display::fillRect(0, floorY, DISPLAY_WIDTH, maxY-floorY, newColor(32, 79, 10));
|
||||
dma_memset(gint_vram + DISPLAY_WIDTH*maxY, (grass << 16) | grass, DISPLAY_WIDTH*DISPLAY_HEIGHT*2 - DISPLAY_WIDTH*maxY*2);
|
||||
#else
|
||||
Display::clear(newColor(70, 180, 220));
|
||||
Display::fillRect(0, floorY, DISPLAY_WIDTH, DISPLAY_HEIGHT-floorY, newColor(32, 79, 19));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
sun.viewMatrix = view;
|
||||
sun.modelMatrix = mat4();
|
||||
sun.modelMatrix = mat4::translate(sun.modelMatrix, 20, -6, -20);
|
||||
|
@ -241,23 +277,19 @@ int main(){
|
|||
sun.modelMatrix = mat4::rotateY(sun.modelMatrix, cameraAngle + HALF_PI);
|
||||
sun.draw(false, false, true);
|
||||
|
||||
floor.viewMatrix = view;
|
||||
floor.draw(false, false, true);
|
||||
|
||||
track.render(view, car.position);
|
||||
|
||||
#ifdef PRIZM
|
||||
enemyCar.render(view);
|
||||
#endif
|
||||
car.render(view);
|
||||
|
||||
char buffer[20];
|
||||
#ifdef SDL
|
||||
#ifdef PRIZM
|
||||
itoa((int)(1.0f / (Time::delta / 128.0f)), (unsigned char*)buffer);
|
||||
#else
|
||||
sprintf(buffer, "%d", (int)(1.0f / (Time::delta / 128.0f)));
|
||||
#endif
|
||||
#ifdef PRIZM
|
||||
// sprintf(fpsBuffer, "%d", (int)Time::delta);
|
||||
itoa((int)(1.0f / (Time::delta / 128.0f)), (unsigned char*)buffer);
|
||||
#endif
|
||||
// Display::fillRect(0, 0, 30, 20, newColor(0, 0, 0));
|
||||
Display::drawText(0, 0, "FPS: ", newColor(255, 255, 255));
|
||||
Display::drawText(Display::textWidth("FPS: "), 0, buffer, newColor(255, 255, 255));
|
||||
|
||||
|
@ -267,11 +299,10 @@ int main(){
|
|||
speed = (1.0f / car.speed.i_length()) * 128.0f / 1000.0f * 3600.0f;
|
||||
else
|
||||
speed = 0;
|
||||
#ifdef SDL
|
||||
sprintf(buffer, "%d", (int)speed);
|
||||
#endif
|
||||
#ifdef PRIZM
|
||||
itoa((int)speed, (unsigned char*)buffer);
|
||||
#else
|
||||
sprintf(buffer, "%d", (int)speed);
|
||||
#endif
|
||||
Display::drawText(0, DISPLAY_HEIGHT-Display::textHeight, "SPEED: ", newColor(255, 255, 255));
|
||||
Display::drawText(Display::textWidth("SPEED: "), DISPLAY_HEIGHT-Display::textHeight, buffer, newColor(255, 255, 255));
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#ifdef GINT
|
||||
static
|
||||
#endif
|
||||
Triangle car_triangles[230] = {
|
||||
{
|
||||
{0.794, 0.294, -0.380},
|
||||
|
@ -1610,6 +1613,9 @@ Triangle car_triangles[230] = {
|
|||
newColor(203, 2, 1)
|
||||
},
|
||||
};
|
||||
#ifdef GINT
|
||||
static
|
||||
#endif
|
||||
Triangle cone_triangles[22] = {
|
||||
{
|
||||
{0.328, -0.679, 0.328},
|
||||
|
|
|
@ -3,6 +3,20 @@
|
|||
#include "rmath.h"
|
||||
#include "time.h"
|
||||
|
||||
#ifdef GINT
|
||||
#include <gint/dma.h>
|
||||
#include <gint/mmu.h>
|
||||
void cache_ocbp(void *buffer, size_t size){
|
||||
for(int i = 0; i < size / 32; i++) {
|
||||
__asm__("ocbp @%0" :: "r"(buffer));
|
||||
buffer += 32;
|
||||
}
|
||||
}
|
||||
void *mmu_translate_uram(void *ptr){
|
||||
return mmu_uram() + ((uint32_t)ptr - 0x08100000);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Plane {
|
||||
vec3<fp> n;
|
||||
fp d;
|
||||
|
@ -23,7 +37,7 @@ inline int max(int a, int b){
|
|||
namespace Rasterizer {
|
||||
Plane clippingPlanes[5];
|
||||
|
||||
fp *depthBuffer;
|
||||
unsigned char *depthBuffer;
|
||||
|
||||
fp fov_d = 1;
|
||||
|
||||
|
@ -36,9 +50,23 @@ namespace Rasterizer {
|
|||
}
|
||||
|
||||
void reset(){
|
||||
for(int i = 0; i < RENDER_WIDTH*RENDER_HEIGHT; i++){
|
||||
depthBuffer[i] = -1;
|
||||
unsigned char value = -1;
|
||||
#if GINT || PRIZM
|
||||
long v = value | (value << 8) | (value << 16) | (value << 24);
|
||||
#endif
|
||||
#if GINT && PIXEL_SIZE == 1
|
||||
unsigned char *depthBuffer_P1 = (unsigned char*) mmu_translate_uram(depthBuffer);
|
||||
cache_ocbp(depthBuffer, RENDER_WIDTH*RENDER_HEIGHT*sizeof(unsigned char));
|
||||
dma_memset(depthBuffer_P1, *((uint32_t*)&v), RENDER_WIDTH*RENDER_HEIGHT*sizeof(unsigned char));
|
||||
#elif PRIZM
|
||||
for(int i = 0; i < RENDER_WIDTH*RENDER_HEIGHT/4; i++){
|
||||
*(((long*)depthBuffer) + i) = v;
|
||||
}
|
||||
#else
|
||||
for(int i = 0; i < RENDER_WIDTH*RENDER_HEIGHT; i++){
|
||||
depthBuffer[i] = value;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void setFOV(int fov){
|
||||
|
@ -76,32 +104,72 @@ namespace Rasterizer {
|
|||
};
|
||||
}
|
||||
|
||||
struct Edge {
|
||||
int minY;
|
||||
int maxY;
|
||||
fp x;
|
||||
fp m;
|
||||
Edge *next;
|
||||
};
|
||||
inline Edge newEdge(vec3<int> p0, vec3<int> p1){
|
||||
if(p0.y > p1.y){
|
||||
return {
|
||||
p1.y,
|
||||
p0.y,
|
||||
p1.x,
|
||||
fp(p0.x - p1.x) / fp(p0.y - p1.y),
|
||||
nullptr
|
||||
};
|
||||
} else if(p0.y < p1.y){
|
||||
return {
|
||||
p0.y,
|
||||
p1.y,
|
||||
p0.x,
|
||||
fp(p1.x - p0.x) / fp(p1.y - p0.y),
|
||||
nullptr
|
||||
};
|
||||
} else {
|
||||
return {p0.y, p1.y, p0.x, 0, nullptr};
|
||||
// Draws a triangle which has a horizontal top or bottom
|
||||
inline void _drawFlatSideTriangle(vec3<int> points[3], unsigned char z, Color color, bool useDepth){
|
||||
if(points[0].y == points[1].y && points[1].y == points[2].y && points[2].y == points[0].y){
|
||||
return;
|
||||
}
|
||||
|
||||
int s = points[0].y < points[1].y;
|
||||
if(!s)
|
||||
s = -1;
|
||||
|
||||
if(s == -1){
|
||||
vec3<int> t = points[0];
|
||||
points[0] = points[2];
|
||||
points[2] = t;
|
||||
}
|
||||
|
||||
// sort horizontal side points by X
|
||||
if(points[1].x > points[2].x){
|
||||
vec3<int> t = points[1];
|
||||
points[1] = points[2];
|
||||
points[2] = t;
|
||||
}
|
||||
|
||||
fp x1 = points[0].x;
|
||||
fp x2 = x1;
|
||||
fp a1 = fp(s) * fp(points[1].x - points[0].x) / fp(points[1].y - points[0].y);
|
||||
fp a2 = fp(s) * fp(points[2].x - points[0].x) / fp(points[2].y - points[0].y);
|
||||
|
||||
int minY = points[0].y;
|
||||
int maxY = points[1].y;
|
||||
for(int y = minY; s*(y - maxY) <= 0; y+=s){
|
||||
if(y > 0 && y < RENDER_HEIGHT-1){
|
||||
int minX = clamp((int)x1, 0, RENDER_WIDTH-1);
|
||||
int maxX = clamp((int)x2, 0, RENDER_WIDTH-1);
|
||||
|
||||
int p = minX+y*RENDER_WIDTH;
|
||||
#ifdef PRIZM
|
||||
unsigned short *vram = Display::VRAMAddress + p;
|
||||
#endif
|
||||
#ifdef GINT
|
||||
color_t *vram = gint_vram + p;
|
||||
#endif
|
||||
|
||||
for(int x = minX; x <= maxX; x++){
|
||||
if(z < depthBuffer[p] || !useDepth){
|
||||
if(useDepth){
|
||||
depthBuffer[p] = z;
|
||||
}
|
||||
#if PIXEL_SIZE == 1
|
||||
#if PRIZM || GINT
|
||||
*vram = color.color;
|
||||
#else
|
||||
Display::drawPoint(x, y, color);
|
||||
#endif
|
||||
#else
|
||||
Display::fillRect(x*PIXEL_SIZE, y*PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, color);
|
||||
#endif
|
||||
}
|
||||
p++;
|
||||
#if PRIZM || GINT
|
||||
vram++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
x1 = x1 + a1;
|
||||
x2 = x2 + a2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,13 +178,13 @@ namespace Rasterizer {
|
|||
vec3<fp> p1_d = toDevice(triangle.p1);
|
||||
vec3<fp> p2_d = toDevice(triangle.p2);
|
||||
|
||||
vec3<int> p0 = toScreen(p0_d);
|
||||
vec3<int> p1 = toScreen(p1_d);
|
||||
vec3<int> p2 = toScreen(p2_d);
|
||||
vec3<int> points[3] = {
|
||||
toScreen(p0_d),
|
||||
toScreen(p1_d),
|
||||
toScreen(p2_d),
|
||||
};
|
||||
|
||||
int minY = max(min(min(p0.y, p1.y), p2.y), 0);
|
||||
int maxY = min(max(max(p0.y, p1.y), p2.y), RENDER_HEIGHT);
|
||||
fp z = (p0.z + p1.z + p2.z) / 3;
|
||||
unsigned char z = (points[0].z + points[1].z + points[2].z) / 3;
|
||||
|
||||
if(isShaded){
|
||||
fp brightness = dot(mat4::toMat3(model->modelMatrix) * triangle.normal, vec3<fp>(I_SQRT_3, -I_SQRT_3, -I_SQRT_3)) * fp(0.6) + fp(0.4);
|
||||
|
@ -130,92 +198,34 @@ namespace Rasterizer {
|
|||
triangle.c = newColor(triangle.c.r, triangle.c.g, triangle.c.b);
|
||||
}
|
||||
|
||||
Edge *edgeTable[RENDER_HEIGHT];
|
||||
Edge edges[3] = {
|
||||
newEdge(p0, p1),
|
||||
newEdge(p1, p2),
|
||||
newEdge(p2, p0),
|
||||
};
|
||||
|
||||
edgeTable[0] = nullptr;
|
||||
for(int i = 0; i < 3; i++){
|
||||
if(edges[i].minY < minY){
|
||||
Edge **e = &(edgeTable[0]);
|
||||
while(*e != nullptr){
|
||||
e = &((*e)->next);
|
||||
}
|
||||
*e = &edges[i];
|
||||
(*e)->x = (*e)->x + fp(-(*e)->minY) * (*e)->m;
|
||||
}
|
||||
}
|
||||
|
||||
for(int y = minY; y < maxY; y++){
|
||||
if(y != 0)
|
||||
edgeTable[y] = nullptr;
|
||||
for(int i = 0; i < 3; i++){
|
||||
if(edges[i].minY == y){
|
||||
Edge **e = &(edgeTable[y]);
|
||||
while(*e != nullptr){
|
||||
e = &((*e)->next);
|
||||
}
|
||||
*e = &edges[i];
|
||||
// sort points by y
|
||||
for(int _i = 0; _i < 2; _i++){
|
||||
for(int i = 0; i < 2; i++){
|
||||
if(points[i].y > points[i+1].y){
|
||||
vec3<int> t = points[i];
|
||||
points[i] = points[i+1];
|
||||
points[i+1] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Edge *activeEdgeList = nullptr;
|
||||
|
||||
for(int y = minY; y < maxY; y++){
|
||||
// add new edges to the list
|
||||
if(edgeTable[y] != nullptr){
|
||||
Edge **e;
|
||||
for(e = &activeEdgeList; *e != nullptr; e = &((*e)->next)){
|
||||
}
|
||||
*e = edgeTable[y];
|
||||
}
|
||||
|
||||
// remove edges from the list
|
||||
for(Edge **e = &activeEdgeList; *e != nullptr;){
|
||||
if(y == (*e)->maxY){
|
||||
*e = (*e)->next;
|
||||
} else {
|
||||
e = &((*e)->next);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate intersection point
|
||||
for(Edge *e = activeEdgeList; e != nullptr; e = e->next){
|
||||
e->x = e->x + e->m;
|
||||
}
|
||||
|
||||
// draw
|
||||
for(Edge *e = activeEdgeList; e != nullptr && e->next != nullptr; e = e->next->next){
|
||||
int a = e->x;
|
||||
int b = e->next->x;
|
||||
if(a < 0) a = 0;
|
||||
else if(a > RENDER_WIDTH) a = RENDER_WIDTH;
|
||||
if(b < 0) b = 0;
|
||||
else if(b > RENDER_WIDTH) b = RENDER_WIDTH;
|
||||
int minX, maxX;
|
||||
if(a > b){
|
||||
maxX = a;
|
||||
minX = b;
|
||||
} else {
|
||||
maxX = b;
|
||||
minX = a;
|
||||
}
|
||||
for(int x = minX; x < maxX; x++){
|
||||
if(z < depthBuffer[x+y*RENDER_WIDTH] || depthBuffer[x+y*RENDER_WIDTH] == -1 || !useDepth){
|
||||
if(useDepth)
|
||||
depthBuffer[x+y*RENDER_WIDTH] = z;
|
||||
#if PIXEL_SIZE == 1
|
||||
Display::drawPoint(x, y, triangle.c);
|
||||
#else
|
||||
Display::fillRect(x*PIXEL_SIZE, y*PIXEL_SIZE, PIXEL_SIZE, PIXEL_SIZE, triangle.c);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
if(points[0].y == points[1].y || points[1].y == points[2].y){
|
||||
_drawFlatSideTriangle(points, z, triangle.c, useDepth);
|
||||
} else {
|
||||
int x = points[0].x + (points[2].x - points[0].x) * (points[1].y - points[0].y) / (points[2].y - points[0].y);
|
||||
vec3<int> newPoint = vec3<int>(x, points[1].y, z);
|
||||
vec3<int> topPoints[3] = {
|
||||
points[0],
|
||||
points[1],
|
||||
newPoint
|
||||
};
|
||||
vec3<int> bottomPoints[3] = {
|
||||
points[1],
|
||||
newPoint,
|
||||
points[2]
|
||||
};
|
||||
_drawFlatSideTriangle(topPoints, z, triangle.c, useDepth);
|
||||
_drawFlatSideTriangle(bottomPoints, z, triangle.c, useDepth);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -346,6 +356,10 @@ namespace Rasterizer {
|
|||
}
|
||||
|
||||
inline void drawTriangle(Model *model, Triangle triangle, bool useDepth, bool isShaded, bool clipTriangles){
|
||||
if(dot(mat4::toMat3(model->viewMatrix) * mat4::toMat3(model->modelMatrix) * triangle.normal, vec3<fp>(0, 0, 1)) > 0){
|
||||
return;
|
||||
}
|
||||
|
||||
triangle.p0 = model->viewMatrix * model->modelMatrix * triangle.p0;
|
||||
triangle.p1 = model->viewMatrix * model->modelMatrix * triangle.p1;
|
||||
triangle.p2 = model->viewMatrix * model->modelMatrix * triangle.p2;
|
||||
|
@ -355,12 +369,14 @@ namespace Rasterizer {
|
|||
}
|
||||
|
||||
int inside = 5;
|
||||
for(int i = 0; i < 5; i++){
|
||||
if(dot(clippingPlanes[i].n, triangle.p0) + clippingPlanes[i].d < 0
|
||||
|| dot(clippingPlanes[i].n, triangle.p1) + clippingPlanes[i].d < 0
|
||||
|| dot(clippingPlanes[i].n, triangle.p2) + clippingPlanes[i].d < 0){
|
||||
inside--;
|
||||
break;
|
||||
if(clipTriangles){
|
||||
for(int i = 0; i < 5; i++){
|
||||
if(dot(clippingPlanes[i].n, triangle.p0) + clippingPlanes[i].d < 0
|
||||
|| dot(clippingPlanes[i].n, triangle.p1) + clippingPlanes[i].d < 0
|
||||
|| dot(clippingPlanes[i].n, triangle.p2) + clippingPlanes[i].d < 0){
|
||||
inside--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -382,8 +398,28 @@ Model::Model(){
|
|||
}
|
||||
Model::Model(Mesh mesh){
|
||||
this->mesh = mesh;
|
||||
fp radius2 = 0;
|
||||
for(int i = 0; i < mesh.numTriangles; i++){
|
||||
fp d0 = mesh.triangles[i].p0.length2();
|
||||
fp d1 = mesh.triangles[i].p1.length2();
|
||||
fp d2 = mesh.triangles[i].p2.length2();
|
||||
radius2 = max(radius2, d0);
|
||||
radius2 = max(radius2, d1);
|
||||
radius2 = max(radius2, d2);
|
||||
}
|
||||
float i_radius = _isqrt(radius2);
|
||||
radius = 1.0f/i_radius;
|
||||
}
|
||||
void Model::draw(bool useDepth, bool isShaded, bool clipTriangles){
|
||||
if(!clipTriangles){
|
||||
vec3<fp> center = viewMatrix * modelMatrix * vec3<fp>(0, 0, 0);
|
||||
for(int i = 0; i < 5; i++){
|
||||
if(dot(Rasterizer::clippingPlanes[i].n, center) + Rasterizer::clippingPlanes[i].d < radius){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < mesh.numTriangles; i++){
|
||||
Rasterizer::drawTriangle(this, mesh.triangles[i], useDepth, isShaded, clipTriangles);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ struct Mesh {
|
|||
};
|
||||
|
||||
class Model {
|
||||
fp radius;
|
||||
public:
|
||||
Mesh mesh;
|
||||
mat4 modelMatrix;
|
||||
|
@ -38,8 +39,9 @@ public:
|
|||
namespace Rasterizer {
|
||||
void init();
|
||||
void reset();
|
||||
extern fp *depthBuffer;
|
||||
extern unsigned char *depthBuffer;
|
||||
|
||||
extern fp fov_d;
|
||||
void setFOV(int fov);
|
||||
|
||||
vec3<fp> toDevice(vec3<fp> p);
|
||||
|
|
|
@ -36,7 +36,7 @@ float _float_sin(float x) {
|
|||
return _float_cos(x - HALF_PI);
|
||||
}
|
||||
|
||||
fp *sinTable = nullptr;
|
||||
static fp sinTable[SIN_SAMPLES];
|
||||
fp _fp_sin(fp x){
|
||||
return fp(_float_sin((float)x));
|
||||
}
|
||||
|
|
10
src/rmath.h
10
src/rmath.h
|
@ -20,7 +20,6 @@ inline fp fp_floor(fp x){
|
|||
}
|
||||
|
||||
#define SIN_SAMPLES 1000
|
||||
extern fp *sinTable;
|
||||
void createSinTable();
|
||||
fp _fp_sin(fp x);
|
||||
|
||||
|
@ -36,3 +35,12 @@ template <typename T>
|
|||
T isqrt(T x){
|
||||
return T(_isqrt(float(x)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T clamp(T v, T min, T max){
|
||||
if(v < min)
|
||||
v = min;
|
||||
else if(v > max)
|
||||
v = max;
|
||||
return v;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#ifdef GINT
|
||||
#include "time.h"
|
||||
#include <gint/rtc.h>
|
||||
#include <libprof.h>
|
||||
|
||||
namespace Time {
|
||||
prof_t prof;
|
||||
void init(){
|
||||
prof_init();
|
||||
prof = prof_make();
|
||||
}
|
||||
void update(){
|
||||
prof_leave(prof);
|
||||
|
||||
const float lastTime = time;
|
||||
time = rtc_ticks();
|
||||
delta = prof_time(prof) / 1000.0f / (1000.0f / 128.0f);
|
||||
|
||||
prof = prof_make();
|
||||
prof_enter(prof);
|
||||
}
|
||||
};
|
||||
#endif
|
|
@ -3,6 +3,8 @@
|
|||
#include <fxcg/rtc.h>
|
||||
|
||||
namespace Time {
|
||||
void init(){
|
||||
}
|
||||
void update(){
|
||||
const float lastTime = time;
|
||||
time = RTC_GetTicks();
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
#include <SDL2/SDL.h>
|
||||
|
||||
namespace Time {
|
||||
void init(){
|
||||
}
|
||||
void update(){
|
||||
const float lastTime = time;
|
||||
time = ((float)(SDL_GetTicks()) / (1000.0/128.0));
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
namespace Time {
|
||||
extern float time;
|
||||
extern float delta;
|
||||
void init();
|
||||
void update();
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ void Track::render(mat4 viewMatrix, vec3<float> carPos){
|
|||
model.viewMatrix = viewMatrix;
|
||||
model.draw(false, false, true);
|
||||
|
||||
for(int i = 0; i < numPoints; i+=1){
|
||||
for(int i = 0; i < numPoints; i+=2){
|
||||
float d = (points[i] - carPos).length2();
|
||||
if(d < 150*150){
|
||||
cones[i*2].mesh = coneMesh;
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef GINT
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include <gint/kmalloc.h>
|
||||
#endif
|
||||
|
||||
#ifdef PRIZM
|
||||
#include <fxcg/heap.h>
|
||||
#include <fxcg/misc.h>
|
||||
|
|
Loading…
Reference in New Issue