Compare commits

...

20 Commits
v1.0 ... master

Author SHA1 Message Date
duarteapcoelho ca63ef88ea Fix freezing because of multiplayer 2022-12-10 16:52:15 +00:00
duarteapcoelho f18108eaee Update README 2022-12-08 20:46:49 +00:00
duarteapcoelho df09c12c07 Clip models 2022-12-08 20:46:42 +00:00
duarteapcoelho 3f1ea2cc5d Fix sun not being visible 2022-12-08 18:00:41 +00:00
duarteapcoelho 98f79eeb05 Do backface culling before anything else 2022-12-08 17:06:40 +00:00
duarteapcoelho 332771104f gint: Add libprof for more accurate FPS 2022-12-08 16:20:43 +00:00
duarteapcoelho 136e536544 Make depth buffer 8 bit 2022-12-08 15:44:53 +00:00
duarteapcoelho 003955e423 Add a 'package' Makefile target to create a release 2022-12-07 15:15:36 +00:00
duarteapcoelho aefbb3cc50 Update README.md 2022-12-07 14:40:12 +00:00
duarteapcoelho 113ea0366a Remove the enemy car from the gint version 2022-12-07 14:39:56 +00:00
duarteapcoelho 7aaaace43b Use a simpler triangle rasterization algorithm 2022-11-29 20:25:58 +00:00
duarteapcoelho b1951208ae Use DMA to draw the grass 2022-11-27 12:19:56 +00:00
duarteapcoelho 96c4b8bdcf Add gint target 2022-11-27 09:09:14 +00:00
duarteapcoelho 9749f08077 Optimize rendering
Reduce index calculations
Draw the grass without using triangles
Reduce the number of cones
Clear the screen using 32 bit writes
2022-11-24 21:45:04 +00:00
duarteapcoelho 0b11ffac4c Add back-face culling 2022-11-16 14:58:28 +00:00
duarteapcoelho 9877547fe1 Remove second image 2022-11-16 13:23:17 +00:00
Duarte Coelho a70d716564 Add video 2022-11-16 12:21:35 +00:00
duarteapcoelho ed3503bb5b Remove unmatched parentheses in README 2022-11-14 18:30:05 +00:00
duarteapcoelho ac2dc37cb2 Fix sub-Makefiles not being updated by main Makefile 2022-11-13 09:00:28 +00:00
duarteapcoelho 53c148d369 Add install instructions to README 2022-11-12 07:31:58 +00:00
33 changed files with 738 additions and 379 deletions

5
.gitignore vendored
View File

@ -4,5 +4,10 @@ prizm/*
sdl/*
!sdl/Makefile
gint/*
!gint/Makefile
resources/models/models.h
resources/models/models.blend1
release

View File

@ -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

View File

@ -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.

32
gint/Makefile Normal file
View File

@ -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)

View File

@ -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

BIN
resources/video.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 MiB

36
src/display-gint.cpp Normal file
View File

@ -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

27
src/display-gint.h Normal file
View File

@ -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;
}
};

View File

@ -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(){}

28
src/display-prizm.h Normal file
View File

@ -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;
}
};

View File

@ -1,7 +1,5 @@
#ifdef SDL
#include "display.h"
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
SDL_Window *window;
SDL_Renderer *renderer;

29
src/display-sdl.h Normal file
View File

@ -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);
}
};

View File

@ -1 +0,0 @@
#include "display.h"

View File

@ -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
};

30
src/input-gint.cpp Normal file
View File

@ -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

61
src/input-gint.h Normal file
View File

@ -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

View File

@ -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};

61
src/input-prizm.h Normal file
View File

@ -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

61
src/input-sdl.h Normal file
View File

@ -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

View File

@ -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 {

View File

@ -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));

View File

@ -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},

View File

@ -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);
}

View File

@ -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);

View File

@ -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));
}

View File

@ -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;
}

23
src/time-gint.cpp Normal file
View File

@ -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

View File

@ -3,6 +3,8 @@
#include <fxcg/rtc.h>
namespace Time {
void init(){
}
void update(){
const float lastTime = time;
time = RTC_GetTicks();

View File

@ -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));

View File

@ -3,5 +3,6 @@
namespace Time {
extern float time;
extern float delta;
void init();
void update();
};

View File

@ -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;

View File

@ -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>