Compare commits

...

10 commits

Author SHA1 Message Date
4a3c9b2873 Continue antiglitch 2024-09-30 02:28:27 +02:00
10366c2a09 Start antiglitch 2024-09-30 01:58:21 +02:00
3310008a0d Clean a bit 2024-09-29 21:41:06 +02:00
beda272f18 Handle start position 2024-09-29 20:52:52 +02:00
34293981b0 Try to handle car turtle 2024-09-28 01:47:05 +02:00
53096517c9 Fix segfault 2024-09-27 00:55:30 +02:00
e9f919052c Add logs and checks 2024-09-27 00:08:52 +02:00
28a1256a88 Fix collision bug 2024-09-26 21:29:36 +02:00
fa66324833 Continue block collisions 2024-09-26 14:56:39 +02:00
011cd891c1 Continue block collisions 2024-09-24 14:48:45 +02:00
9 changed files with 506 additions and 190 deletions

View file

@ -1,10 +1,5 @@
- allow car to be flipped upside down on start? with start block transform
- maybe change sticker to fan? could me more fun: TEST and see
- based viewing distance idea: limit number of rendered map triangles to N, keep
sorting the triangle array by distance continually! e.g. in each frame handle
one of the N visible triangles like this -- in the non-visible triangles
find one that is closer than this and switch them (if found).
- sky images could be just composed of 4x4 normal images? then we only need
one type of image
- map actually in ASCII format? how will humans edit it?
- make a simple rendering setting:
- will exclude images and only draw solid colors, let's say only 16, so that
@ -16,19 +11,7 @@
- then iterate over the strip that should have the sky texture and only draw
to pixels where depth buffer was not overwritten (this step can be left out
in case we have depth buffer or sky turned off)
TOTAL SIZE OF TEXTURES:
- 64 x 64 x 2 = 8192, 6 x floor + 2 x wall + 1 x car = 8 * 8192 = 73728
- (128 x 128 x 1) x 3 background = 49152
- total = 122880
- OK so materials (final?):
- concrete: normal \
- accelerator: accelerates (adds some constant to speed?) > same wall texture?
- maybe jumppad (big "fan")? /
- dirt: a bit slippery (maybe also a bit slows down?) \
- magnet: pulls car downwards (allows riding on ceiling etc.) > same wall texture?
- ice: extremely slippery (can barely turn) /
- camera behavior? what if car is riding upside down (on magnet) etc?
- track size: 64x64x64
- EFFICINT MAP DRAWING:
- map will be subdivided into subblocks (probably 16x16x16 or 8x8x8), only
nearest subblocks (and possibly only those in viewing direction will be
@ -41,14 +24,6 @@ TOTAL SIZE OF TEXTURES:
subblocks we want to draw.
- THIS??? Draw further blocks in a simplified way, e.g. just splatting literal
squares with constant color? See how it looks :)
- Architecture (modules):
- map: loads map n stuff
- racing engine (depends on map): handles physics of car with given inputs
- rendering engine (depends on map): hanles rendering of the map
- game (depends on all): joins it all together
- settings, constants etc.
- individual frontends
- ...?
- Textures: size? format? They will likely take a lot of mem, weak computers
will have to do without them.
- possibility of simple procedural textures to save space! <-- SOUNDS NICE
@ -140,4 +115,27 @@ TOTAL SIZE OF TEXTURES:
BUGS:
DONE:
HANDLED:
- track size: 64x64x64
- sky images could be just composed of 4x4 normal images? then we only need
one type of image
TOTAL SIZE OF TEXTURES:
- 64 x 64 x 2 = 8192, 6 x floor + 2 x wall + 1 x car = 8 * 8192 = 73728
- (128 x 128 x 1) x 3 background = 49152
- total = 122880
- OK so materials (final?):
- concrete: normal \
- accelerator: accelerates (adds some constant to speed?) > same wall texture?
- maybe jumppad (big "fan")? /
- dirt: a bit slippery (maybe also a bit slows down?) \
- magnet: pulls car downwards (allows riding on ceiling etc.) > same wall texture?
- ice: extremely slippery (can barely turn) /
- Architecture (modules):
- map: loads map n stuff
- racing engine (depends on map): handles physics of car with given inputs
- rendering engine (depends on map): hanles rendering of the map
- game (depends on all): joins it all together
- settings, constants etc.
- individual frontends
- ...?

110
assets.h
View file

@ -16,8 +16,6 @@
#include <stdint.h>
#include "map.h"
// TODO: images should be 64x64 indexed, sky will be composed of 2x2 normal images
static const uint8_t map1[] =
{
LCR_MAP_MAGIC_NUMBER,
@ -26,86 +24,54 @@ static const uint8_t map1[] =
10,
0,
LCR_MAP_BLOCK(LCR_BLOCK_START,1,1,1,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP,36,0,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP_34,20,0,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP_12,32,0,37,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP_14,32,0,20,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,0,0,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,15,1,20,0,0),
/*
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,0,0,0,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,63,1,1,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,0,20,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,10,15,1,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,0,0,63,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,63,1,1,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP,0,1,19,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,8,1,1,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,0,0,0,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,1,1,63,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP,8,1,5,LCR_BLOCK_MATERIAL_CONCRETE,LCR_BLOCK_TRANSFORM_ROT_270),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,1,1,8,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,63,0,0,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,1,1,63,0,0),
*/
LCR_MAP_BLOCK(LCR_BLOCK_LEFT,5,1,5,LCR_BLOCK_MATERIAL_CONCRETE,LCR_BLOCK_TRANSFORM_ROT_90),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,10,2,1,0,0),
/*
LCR_MAP_BLOCK(LCR_BLOCK_FULL_ACCEL,32,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,4,4,4,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,50,20,20,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,5,5,5,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_LEFT,9,0,20,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,8,1,8,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,10,10,10,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,3,3,3,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,2,25,50,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,3,3,3,0,0),
*/
LCR_MAP_BLOCK(LCR_BLOCK_FULL,15,0,0,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,10,1,15,0,0),
/*
LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,0,0,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,40,1,1,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,25,0,0,LCR_BLOCK_MATERIAL_ICE,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,10,1,15,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,63,63,0,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,1,1,40,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,35,0,0,LCR_BLOCK_MATERIAL_DIRT,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_FILL,10,1,15,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,15,0,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,7,4,8,0,0),
*/
/*
LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,15,0,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_CUBOID_HOLLOW,7,4,8,0,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,32,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,32,32,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP_CURVED_WALL,34,32,32,LCR_BLOCK_MATERIAL_GRASS,0),
LCR_MAP_BLOCK(LCR_BLOCK_RAMP_CURVED_WALL,35,32,32,LCR_BLOCK_MATERIAL_CONCRETE,LCR_BLOCK_TRANSFORM_ROT_90),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,63,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,0,35,32,LCR_BLOCK_MATERIAL_ICE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,40,35,32,LCR_BLOCK_MATERIAL_DIRT,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,41,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,42,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,43,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,44,35,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_BOTTOM_LEFT,34,32,33,LCR_BLOCK_MATERIAL_CONCRETE,LCR_BLOCK_TRANSFORM_ROT_90),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,33,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,33,32,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,33,33,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,33,33,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,32,32,33,LCR_BLOCK_MATERIAL_CONCRETE,0),
LCR_MAP_BLOCK(LCR_BLOCK_FULL,33,32,33,LCR_BLOCK_MATERIAL_CONCRETE,0),
*/
LCR_MAP_TERMINATOR
};
#define LCR_IMAGE_SIZE 64 ///< one-dimension resolution of bitmap image
#define LCR_IMAGE_STORE_SIZE (LCR_IMAGE_SIZE * LCR_IMAGE_SIZE + 256 * 2)
// TODO: put this into struct
uint16_t _LCR_currentImagePalette[256];
const uint8_t *_LCR_currentImagePixel;
const uint8_t *_LCR_currentImage;
struct
{
uint16_t palette[256];
const uint8_t *pixel;
const uint8_t *image;
} LCR_currentImage;
#define LCR_IMAGE_WALL_CONCRETE 0
#define LCR_IMAGE_WALL_WOOD 1
@ -6192,17 +6158,17 @@ static const uint8_t LCR_images[] =
void LCR_loadImage(unsigned int index)
{
_LCR_currentImage = LCR_images + index * LCR_IMAGE_STORE_SIZE;
LCR_currentImage.image = LCR_images + index * LCR_IMAGE_STORE_SIZE;
for (int i = 0; i < 256; ++i)
{
_LCR_currentImagePalette[i] = *_LCR_currentImage;
_LCR_currentImage++;
_LCR_currentImagePalette[i] |= ((uint16_t) (*_LCR_currentImage)) << 8;
_LCR_currentImage++;
LCR_currentImage.palette[i] = *LCR_currentImage.image;
LCR_currentImage.image++;
LCR_currentImage.palette[i] |= ((uint16_t) (*LCR_currentImage.image)) << 8;
LCR_currentImage.image++;
}
_LCR_currentImagePixel = _LCR_currentImage;
LCR_currentImage.pixel = LCR_currentImage.image;
}
/**
@ -6213,11 +6179,11 @@ void LCR_imageChangeBrightness(int up)
{
if (up)
for (int i = 0; i < 256; ++i)
_LCR_currentImagePalette[i] |= 0x18e3;
LCR_currentImage.palette[i] |= 0x18e3;
else
for (int i = 0; i < 256; ++i)
_LCR_currentImagePalette[i] =
((_LCR_currentImagePalette[i] >> 1) & 0x7bef);
LCR_currentImage.palette[i] =
((LCR_currentImage.palette[i] >> 1) & 0x7bef);
}
/**
@ -6229,7 +6195,7 @@ uint16_t LCR_sampleImage(int x, int y)
// TODO: bottleneck, later on optimize here
x = (y % LCR_IMAGE_SIZE) * LCR_IMAGE_SIZE + (x % LCR_IMAGE_SIZE);
x += (x < 0) * (LCR_IMAGE_SIZE * LCR_IMAGE_SIZE);
return _LCR_currentImagePalette[_LCR_currentImage[x]];
return LCR_currentImage.palette[LCR_currentImage.image[x]];
}
/**
@ -6238,8 +6204,8 @@ uint16_t LCR_sampleImage(int x, int y)
*/
uint16_t LCR_getNextImagePixel(void)
{
uint16_t r = _LCR_currentImagePalette[*_LCR_currentImagePixel];
_LCR_currentImagePixel++;
uint16_t r = LCR_currentImage.palette[*LCR_currentImage.pixel];
LCR_currentImage.pixel++;
return r;
}

View file

@ -1,6 +1,8 @@
#include <stdio.h>
#include <SDL2/SDL.h>
#define LCR_SETTING_LOG_LEVEL 2
#include "game.h"
#include "debug.h"
@ -67,12 +69,30 @@ int main(int argc, char *argv[])
SDL_WINDOWPOS_UNDEFINED, LCR_SETTING_RESOLUTION_X, LCR_SETTING_RESOLUTION_Y,
SDL_WINDOW_SHOWN);
if (!window)
{
fputs("ERROR: couldn't create window",stderr);
return 1;
}
renderer = SDL_CreateRenderer(window,-1,0);
if (!renderer)
{
fputs("ERROR: couldn't create renderer",stderr);
return 1;
}
texture =
SDL_CreateTexture(renderer,SDL_PIXELFORMAT_RGB565,SDL_TEXTUREACCESS_STATIC,
LCR_SETTING_RESOLUTION_X,LCR_SETTING_RESOLUTION_Y);
if (!texture)
{
fputs("ERROR: couldn't create texture",stderr);
return 1;
}
screenSurface = SDL_GetWindowSurface(window);
SDL_ShowCursor(0);

29
game.h
View file

@ -94,6 +94,25 @@ uint8_t LCR_gameStep(uint32_t timeMs);
//------------------------------------------------------------------------------
#define LCR_LOG0(s) ;
#define LCR_LOG1(s) ;
#define LCR_LOG2(s) ;
#if LCR_SETTING_LOG_LEVEL > 0
#undef LCR_LOG0
#define LCR_LOG0(s) LCR_log(s);
#if LCR_SETTING_LOG_LEVEL > 1
#undef LCR_LOG1
#define LCR_LOG1(s) LCR_log(s);
#if LCR_SETTING_LOG_LEVEL > 2
#undef LCR_LOG2
#define LCR_LOG2(s) LCR_log(s);
#endif
#endif
#endif
#define LCR_CONTROL_MODE_FREECAM 0x00
#define LCR_CONTROL_MODE_DRIVE 0x01
@ -144,7 +163,7 @@ static inline void LCR_drawPixelXYSafe(unsigned int x, unsigned int y,
void LCR_gameInit(void)
{
LCR_log("initializing");
LCR_LOG0("initializing");
for (int i = 0; i < LCR_KEYS_TOTAL; ++i)
LCR_keyStates[i] = 0;
@ -162,10 +181,13 @@ void LCR_gameInit(void)
void LCR_gameEnd(void)
{
LCR_LOG0("ending");
}
uint8_t LCR_gameStep(uint32_t time)
{
LCR_LOG2("game step start");
for (int i = 0; i < LCR_KEYS_TOTAL; ++i)
LCR_keyStates[i] = LCR_keyPressed(i) ?
(LCR_keyStates[i] < 255 ? LCR_keyStates[i] + 1 : 255) : 0;
@ -188,6 +210,7 @@ if ((LCR_racing.tick % 32) == 0)
while (time >= LCR_game.nextRacingTickTime)
{
LCR_LOG2("gonna step racing engine");
unsigned int input = 0;
if (LCR_game.controlMode != LCR_CONTROL_MODE_FREECAM)
@ -205,6 +228,8 @@ if ((LCR_racing.tick % 32) == 0)
if (time >= LCR_game.nextRenderFrameTime)
{
LCR_LOG2("gonna render next frame");
LCR_GameUnit physicsInterpolationParam = LCR_GAME_UNIT -
((LCR_game.nextRacingTickTime - time) * LCR_GAME_UNIT) /
LCR_RACING_TICK_MS;
@ -278,6 +303,8 @@ LCR_GameUnit physicsInterpolationParam = LCR_GAME_UNIT -
if (sleep)
LCR_sleep(sleep);
LCR_LOG2("game step end");
return 1;
}

92
map.h
View file

@ -84,7 +84,6 @@
#define LCR_BLOCK_RAMP_CURVED_SHORT 0x0a
#define LCR_BLOCK_RAMP_CURVED_WALL 0x0b
#define LCR_BLOCK_FULL_ACCEL 0x20
#define LCR_BLOCK_FULL_FAN 0x30
@ -105,7 +104,7 @@ struct
{
uint16_t blockCount;
uint8_t blocks[LCR_SETTING_MAP_MAX_BLOCKS * LCR_BLOCK_SIZE];
uint32_t startPos;
uint8_t startPos[4]; ///< Initial position and rotation.
uint8_t environment;
@ -149,6 +148,20 @@ void LCR_mapBlockGetCoords(const uint8_t block[LCR_BLOCK_SIZE],
*z = (block[2] >> 4) | ((block[3] & 0x03) << 4);
}
uint8_t LCR_mapBlockOppositeTransform(uint8_t transform)
{
if (!(transform & LCR_BLOCK_TRANSFORM_FLIP_H))
{
if ((transform & 0x60) == LCR_BLOCK_TRANSFORM_ROT_90)
return ((transform & (~0x60)) | LCR_BLOCK_TRANSFORM_ROT_270);
if ((transform & 0x60) == LCR_BLOCK_TRANSFORM_ROT_270)
return ((transform & (~0x60)) | LCR_BLOCK_TRANSFORM_ROT_90);
}
return transform;
}
uint8_t LCR_mapBlockGetTransform(const uint8_t block[LCR_BLOCK_SIZE])
{
return block[3] & 0xf0;
@ -172,6 +185,15 @@ uint32_t LCR_mapBlockCoordsToCoordNumber(uint8_t x, uint8_t y, uint8_t z)
return LCR_mapBlockGetCoordNumber(b);
}
int LCR_rampHeight4ths(uint8_t rampType)
{
return
(rampType == LCR_BLOCK_RAMP_14) +
(rampType == LCR_BLOCK_RAMP) * 4 +
(rampType == LCR_BLOCK_RAMP_12 || rampType == LCR_BLOCK_RAMP_34) * 2 +
(rampType == LCR_BLOCK_RAMP_34);
}
uint8_t *LCR_getMapBlockAtCoordNumber(uint32_t coord)
{
// binary search the block:
@ -205,6 +227,8 @@ uint8_t *LCR_getMapBlockAtCoordNumber(uint32_t coord)
*/
uint8_t _LCR_mapAddBlock(const uint8_t block[LCR_BLOCK_SIZE])
{
LCR_LOG2("adding map block");
if (LCR_currentMap.blockCount >= LCR_SETTING_MAP_MAX_BLOCKS)
return 0;
@ -261,7 +285,11 @@ uint8_t _LCR_mapAddBlock(const uint8_t block[LCR_BLOCK_SIZE])
*/
uint8_t LCR_mapLoad(const uint8_t *map)
{
LCR_currentMap.startPos = 0;
LCR_LOG0("loading map")
for (int i = 0; i < 4; ++i)
LCR_currentMap.startPos[i] = 0;
LCR_currentMap.blockCount = 0;
if (map[0] != LCR_MAP_MAGIC_NUMBER1 || map[1] != LCR_MAP_MAGIC_NUMBER2)
@ -326,6 +354,15 @@ uint8_t LCR_mapLoad(const uint8_t *map)
break;
}
case LCR_BLOCK_START:
LCR_mapBlockGetCoords(map,
LCR_currentMap.startPos,
LCR_currentMap.startPos + 1,
LCR_currentMap.startPos + 2);
LCR_currentMap.startPos[3] = LCR_mapBlockGetTransform(map) & 0x60;
break;
default:
if (!_LCR_mapAddBlock(map)) // normal block
return 0;
@ -333,16 +370,10 @@ uint8_t LCR_mapLoad(const uint8_t *map)
break;
}
map += 4;
map += LCR_BLOCK_SIZE;
}
// process and remove special blocks:
// TODO
// sort the blocks (for fast searching):
// TODO
LCR_LOG2("map loaded")
return 1;
}
@ -425,6 +456,20 @@ void _LCR_addBlockShapeByte(uint8_t *bytes, uint8_t *byteCount,
*byteCount += 1;
}
/**
Macro that transforms coordinates according to block transformation.
*/
#define LCR_TRANSFORM_COORDS(trans,cx,cy,cz,maxXZ,maxY)\
if (trans & LCR_BLOCK_TRANSFORM_FLIP_H) cx = maxXZ - cx;\
if (trans & 0x20) { /* for both 90 and 270 */ \
cx ^= cz; cz ^= cx; cx ^= cz; /* swap */ \
cx = maxXZ - cx; } \
if (trans & 0x40) { /* for both 180 and 270 */ \
cx = maxXZ - cx; \
cz = maxXZ - cz; } \
if (trans & LCR_BLOCK_TRANSFORM_FLIP_V) \
cy = maxY - cy;
/**
Gets a shape of given map block type as a 3D model composed of triangles. The
model is returned as an array of byte triplets (triangles), with each byte
@ -522,11 +567,7 @@ void LCR_mapGetBlockShape(uint8_t blockType, uint8_t transform,
case LCR_BLOCK_RAMP_14:
case LCR_BLOCK_RAMP_34:
{
uint8_t top =
(blockType == LCR_BLOCK_RAMP_14) +
(blockType == LCR_BLOCK_RAMP) * 4 +
(blockType == LCR_BLOCK_RAMP_12 || blockType == LCR_BLOCK_RAMP_34) * 2 +
(blockType == LCR_BLOCK_RAMP_34);
uint8_t top = LCR_rampHeight4ths(blockType);
ADD(0,0,0) ADD(0,top,6) ADD(0,0,6) // side
ADD(6,0,0) ADD(6,0,6) ADD(6,top,6) // side
@ -551,24 +592,7 @@ void LCR_mapGetBlockShape(uint8_t blockType, uint8_t transform,
_LCR_decodeMapBlockCoords(bytes[i],&x,&y,&z);
if (transform & LCR_BLOCK_TRANSFORM_FLIP_H)
x = 6 - x;
if (transform & 0x20) // for both 90 and 270
{
tmp = z;
z = x;
x = 6 - tmp;
}
if (transform & 0x40) // for both 180 and 270
{
x = 6 - x;
z = 6 - z;
}
if (transform & LCR_BLOCK_TRANSFORM_FLIP_V)
y = 4 - y;
LCR_TRANSFORM_COORDS(transform,x,y,z,6,4)
bytes[i] = _LCR_encodeMapBlockCoords(x,y,z);
}

298
racing.h
View file

@ -16,17 +16,21 @@ typedef int32_t LCR_GameUnit; ///< abstract game unit
#define LCR_PHYSICS_UNIT 2048 ///< length of map square for physics engine
#define TPE_RESHAPE_TENSION_LIMIT 10
#define TPE_RESHAPE_ITERATIONS 5
#include "map.h"
#include "tinyphysicsengine.h"
// TODO: move some of this to constants?
#define LCR_GRAVITY (LCR_PHYSICS_UNIT / 100)
#define LCR_CAR_FORWARD_FRICTION (TPE_F / 11)
#define LCR_CAR_TURN_FRICTION (4 * TPE_F / 4)
#define LCR_CAR_ELASTICITY (TPE_F / 100)
#define LCR_CAR_ACCELERATION (LCR_PHYSICS_UNIT / 15)
#define LCR_CAR_TURN_SPEED (LCR_GAME_UNIT / 20)
#define LCR_CAR_TURN_MAX (LCR_GAME_UNIT / 4)
#define LCR_GRAVITY (LCR_PHYSICS_UNIT / 140)
#define LCR_CAR_FORWARD_FRICTION (TPE_F / 9)
#define LCR_CAR_TURN_FRICTION (TPE_F)
#define LCR_CAR_ELASTICITY (TPE_F / 110)
#define LCR_CAR_ACCELERATION (LCR_PHYSICS_UNIT / 16)
#define LCR_CAR_TURN_SPEED (LCR_GAME_UNIT / 18)
#define LCR_CAR_TURN_MAX ((7 * LCR_GAME_UNIT) / 24)
#define LCR_CAR_JOINTS 5
#define LCR_CAR_CONNECTIONS 10
@ -43,9 +47,13 @@ struct
Lower bits record current collisions, higher
bits the previous state (for averaging). */
TPE_Vec3 carPositions[2]; ///* Current and previous position in game units.
TPE_Vec3 carRotations[2]; ///* Current and previous rotation in game units.
TPE_Vec3 carOKPositions[LCR_CAR_JOINTS];
uint8_t carNotOKCount;
TPE_Vec3 carPositions[2]; ///* Current and previous position.
TPE_Vec3 carRotations[2]; ///* Current and previous rotation.
LCR_GameUnit wheelRotation;
LCR_GameUnit wheelSteer;
@ -62,16 +70,99 @@ TPE_Vec3 _LCR_racingBlockEnvFunc(TPE_Vec3 point, const uint8_t *block)
uint8_t bx, by, bz;
LCR_mapBlockGetCoords(block,&bx,&by,&bz);
TPE_Vec3 center = TPE_vec3(
(((int) bx) - LCR_MAP_SIZE_BLOCKS / 2) * LCR_PHYSICS_UNIT
+ LCR_PHYSICS_UNIT / 2,
(((int) by) - LCR_MAP_SIZE_BLOCKS / 2) * (LCR_PHYSICS_UNIT / 2)
+ LCR_PHYSICS_UNIT / 4,
(((int) bz) - LCR_MAP_SIZE_BLOCKS / 2) * LCR_PHYSICS_UNIT
+ LCR_PHYSICS_UNIT / 2);
TPE_Vec3 blockOffset = TPE_vec3(
(((int) bx) - LCR_MAP_SIZE_BLOCKS / 2) * LCR_PHYSICS_UNIT,
(((int) by) - LCR_MAP_SIZE_BLOCKS / 2) * (LCR_PHYSICS_UNIT / 2),
(((int) bz) - LCR_MAP_SIZE_BLOCKS / 2) * LCR_PHYSICS_UNIT);
return TPE_envAABox(point,center,TPE_vec3(LCR_PHYSICS_UNIT / 2,
LCR_PHYSICS_UNIT / 4,LCR_PHYSICS_UNIT / 2));
point = TPE_vec3Minus(point,blockOffset); // shift to origin
uint8_t transform =
LCR_mapBlockOppositeTransform(LCR_mapBlockGetTransform(block));
LCR_TRANSFORM_COORDS(transform,point.x,point.y,point.z,LCR_PHYSICS_UNIT,
(LCR_PHYSICS_UNIT / 2))
point = TPE_vec3Minus(point,
TPE_vec3(LCR_PHYSICS_UNIT / 2,LCR_PHYSICS_UNIT / 4,LCR_PHYSICS_UNIT / 2));
switch (block[0])
{
case LCR_BLOCK_FULL:
case LCR_BLOCK_BOTTOM:
case LCR_BLOCK_LEFT:
case LCR_BLOCK_BOTTOM_LEFT:
case LCR_BLOCK_BOTTOM_LEFT_FRONT:
case LCR_BLOCK_FULL_ACCEL:
case LCR_BLOCK_FULL_FAN:
{
TPE_Vec3
offset = TPE_vec3(0,0,0),
size = TPE_vec3(LCR_PHYSICS_UNIT / 2,LCR_PHYSICS_UNIT / 4,
LCR_PHYSICS_UNIT / 2);
if (block[0] == LCR_BLOCK_BOTTOM ||
block[0] == LCR_BLOCK_BOTTOM_LEFT ||
block[0] == LCR_BLOCK_BOTTOM_LEFT_FRONT)
{
offset.y -= LCR_PHYSICS_UNIT / 8;
size.y = LCR_PHYSICS_UNIT / 8;
}
if (block[0] == LCR_BLOCK_LEFT ||
block[0] == LCR_BLOCK_BOTTOM_LEFT ||
block[0] == LCR_BLOCK_BOTTOM_LEFT_FRONT)
{
offset.x -= LCR_PHYSICS_UNIT / 4;
size.x = LCR_PHYSICS_UNIT / 4;
}
if (block[0] == LCR_BLOCK_BOTTOM_LEFT_FRONT)
{
offset.z -= LCR_PHYSICS_UNIT / 4;
size.z = LCR_PHYSICS_UNIT / 4;
}
point = TPE_envAABox(point,offset,size);
break;
}
case LCR_BLOCK_RAMP:
case LCR_BLOCK_RAMP_34:
case LCR_BLOCK_RAMP_12:
case LCR_BLOCK_RAMP_14:
{
TPE_Unit sides[6];
sides[0] = -1 * LCR_PHYSICS_UNIT / 2;
sides[1] = -1 * LCR_PHYSICS_UNIT / 4;
sides[2] = LCR_PHYSICS_UNIT / 2;
sides[3] = -1 * LCR_PHYSICS_UNIT / 4;
sides[4] = LCR_PHYSICS_UNIT / 2;
sides[5] = -1 * LCR_PHYSICS_UNIT / 4 +
LCR_rampHeight4ths(block[0]) * (LCR_PHYSICS_UNIT / 8);
point = TPE_envAATriPrism(point,TPE_vec3(0,0,0),sides,LCR_PHYSICS_UNIT,2);
break;
}
default:
point = TPE_vec3(0,0,LCR_MAP_SIZE_BLOCKS * LCR_PHYSICS_UNIT);
break;
}
point = TPE_vec3Plus(point,
TPE_vec3(LCR_PHYSICS_UNIT / 2,LCR_PHYSICS_UNIT / 4,LCR_PHYSICS_UNIT / 2));
transform = LCR_mapBlockOppositeTransform(transform);
LCR_TRANSFORM_COORDS(transform,point.x,point.y,point.z,LCR_PHYSICS_UNIT,
(LCR_PHYSICS_UNIT / 2))
point = TPE_vec3Plus(point,blockOffset); // shift back
return point;
}
TPE_Vec3 _LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
@ -82,6 +173,10 @@ TPE_Vec3 _LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
(LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS) / 2,
LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS)),point)
// without this check we might try to get block outside the map
if (_pBest.x == point.x && _pBest.y == point.y && _pBest.z == point.z)
return _pBest;
if (maxDist <= LCR_PHYSICS_UNIT / 4) // considering half of square height
{
/* Here we only check the 8 closest blocks => relatively fast. */
@ -142,7 +237,8 @@ TPE_Vec3 _LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
}
else
{
printf("oof\n");
LCR_LOG1("collision checking all blocks (shouldn't happen often!)");
const uint8_t *block = LCR_currentMap.blocks;
/* Full check of all map blocks, slow, shouldn't happen often! */
@ -195,6 +291,8 @@ LCR_GameUnit _LCR_racingSmoothRot(LCR_GameUnit angleNew, LCR_GameUnit angleOld)
*/
void LCR_racingRestart(void)
{
LCR_LOG0("restarting race");
LCR_racing.tick = 0;
TPE_bodyActivate(&(LCR_racing.carBody));
@ -208,15 +306,43 @@ void LCR_racingRestart(void)
LCR_racing.carRotations[0] = TPE_vec3(0,0,0);
LCR_racing.carRotations[1] = LCR_racing.carRotations[0];
TPE_bodyMoveTo(&(LCR_racing.carBody),
TPE_vec3(
(((TPE_Unit) LCR_currentMap.startPos[0]) - LCR_MAP_SIZE_BLOCKS / 2)
* LCR_PHYSICS_UNIT + LCR_PHYSICS_UNIT / 2,
(((TPE_Unit) LCR_currentMap.startPos[1]) - LCR_MAP_SIZE_BLOCKS / 2)
* LCR_PHYSICS_UNIT / 2 + LCR_PHYSICS_UNIT / 4,
(((TPE_Unit) LCR_currentMap.startPos[2]) - LCR_MAP_SIZE_BLOCKS / 2)
* LCR_PHYSICS_UNIT + LCR_PHYSICS_UNIT / 2));
// TODO: allow also flipping the car upside down on start?
if (LCR_currentMap.startPos[3])
TPE_bodyRotateByAxis(&(LCR_racing.carBody),
TPE_vec3(0,
LCR_currentMap.startPos[3] == LCR_BLOCK_TRANSFORM_ROT_90 ? 3 * TPE_F / 4 :
(LCR_currentMap.startPos[3] == LCR_BLOCK_TRANSFORM_ROT_180 ? TPE_F / 2 :
(TPE_F / 4)),0));
for (int i = 0; i < LCR_CAR_JOINTS; ++i)
LCR_racing.carOKPositions[i] = TPE_vec3(0,0,0);
LCR_racing.carNotOKCount = 0;
// TODO
}
/**
Initializes the racing module, only call once.
*/
void LCR_racingInit(void)
{
LCR_log("initializing racing engine");
LCR_LOG0("initializing racing engine");
// make the car body:
TPE_makeCenterRectFull(LCR_racing.carJoints,
@ -257,6 +383,8 @@ void LCR_racingInit(void)
void LCR_racingGetCarTransform(LCR_GameUnit position[3],
LCR_GameUnit rotation[3], LCR_GameUnit interpolationParam)
{
LCR_LOG2("getting car transform");
TPE_Vec3 v;
#if LCR_SETTING_SMOOTH_ANIMATIONS
@ -326,11 +454,28 @@ void _LCR_racingWheelAccelerate(unsigned int wheel, TPE_Vec3 dir)
(dir.z * LCR_CAR_ACCELERATION) / TPE_F;
}
int _LCR_racingCarShapeOK(void)
{
int r = 1;
for (int i = 0; i < LCR_racing.carBody.jointCount; ++i)
r &= TPE_connectionTension(TPE_dist(
LCR_racing.carBody.joints[
LCR_racing.carBody.connections[i].joint1].position,
LCR_racing.carBody.joints[
LCR_racing.carBody.connections[i].joint2].position),
LCR_racing.carBody.connections[i].length) < TPE_F / 16; // TODO: const
return r;
}
/**
Updates the racing physics world, call every LCR_RACING_TICK_MS milliseconds.
*/
void LCR_racingStep(unsigned int input)
{
LCR_LOG2("racing step start");
TPE_Vec3 carForw, carRight, carUp;
carForw = TPE_vec3Normalized(TPE_vec3Plus(
@ -438,35 +583,35 @@ void LCR_racingStep(unsigned int input)
(!(input & LCR_RACING_INPUT_RIGHT)))
LCR_racing.wheelSteer /= 2;
if ((LCR_racing.wheelCollisions & 0x0f) != 0x0f) // EXPERIMENTAL: don't apply gravity with all wheels on ground
TPE_bodyApplyGravity(&(LCR_racing.carBody),LCR_GRAVITY);
LCR_racing.wheelCollisions <<= 4;
LCR_LOG2("gonna step physics engine");
TPE_worldStep(&(LCR_racing.physicsWorld));
LCR_LOG2("stepping physics engine done");
if (TPE_vec3Dot(carUp,TPE_vec3Minus(LCR_racing.carBody.joints[4].position,
LCR_racing.carBody.joints[0].position)) < 0)
{
/* if the car falls on its roof the center joint may flip to the other
side, here we fix it */
LCR_racing.carBody.joints[4].position = TPE_vec3Plus(TPE_vec3Times(carUp,
LCR_GAME_UNIT / 4),LCR_racing.carBody.joints[4].position);
}
TPE_Vec3 tmpVec = LCR_racing.carPositions[0];
LCR_racing.carPositions[0] = // average position of 4 wheels to get car pos
_LCR_TPE_vec3DividePlain(
TPE_vec3TimesPlain(
TPE_vec3Plus(
TPE_Vec3 wheelAverage =
_LCR_TPE_vec3DividePlain(
TPE_vec3Plus(
TPE_vec3Plus(
LCR_racing.carBody.joints[0].position,
LCR_racing.carBody.joints[1].position),
TPE_vec3Plus(
LCR_racing.carBody.joints[2].position,
LCR_racing.carBody.joints[3].position)
),LCR_GAME_UNIT),4 * LCR_PHYSICS_UNIT);
LCR_racing.carBody.joints[3].position)),4);
LCR_racing.carPositions[0] =
_LCR_TPE_vec3DividePlain(
TPE_vec3TimesPlain(
wheelAverage,LCR_GAME_UNIT),
LCR_PHYSICS_UNIT);
LCR_racing.carPositions[0] = // smooth the position
TPE_vec3KeepWithinBox(LCR_racing.carPositions[1],LCR_racing.carPositions[0],
@ -483,12 +628,93 @@ void LCR_racingStep(unsigned int input)
LCR_racing.carRotations[1] = LCR_racing.carRotations[0];
LCR_racing.carRotations[0] = tmpVec;
TPE_Unit angle =
TPE_vec3Dot(carUp,TPE_vec3Normalized(TPE_vec3Minus(
LCR_racing.carBody.joints[4].position,
LCR_racing.carBody.joints[0].position)));
if (angle < TPE_F / 4) // TODO: magic constant
{
LCR_LOG2("roof squeezed, applying anti force")
tmpVec = TPE_vec3Times(carUp,LCR_PHYSICS_UNIT / 16); // TODO: 16 magic con.
if (angle <= 0)
{
LCR_LOG1("roof flipped over, fixing")
LCR_racing.carBody.joints[4].position = wheelAverage;
angle = 0;
}
angle = TPE_F - 4 * angle; // 4 comes from above TPE_F / 4
tmpVec = TPE_vec3Times(tmpVec,angle);
// accelerate roof and wheels away from each other
for (int i = 0; i < LCR_CAR_JOINTS; ++i)
{
LCR_racing.carBody.joints[i].velocity[0] += (i == 4 ? 1 : -1) * tmpVec.x;
LCR_racing.carBody.joints[i].velocity[1] += (i == 4 ? 1 : -1) * tmpVec.y;
LCR_racing.carBody.joints[i].velocity[2] += (i == 4 ? 1 : -1) * tmpVec.z;
}
}
if ((LCR_racing.carBody.flags & TPE_BODY_FLAG_UNRESOLVED) ||
!_LCR_racingCarShapeOK())
{
// car not OK
if (LCR_racing.carNotOKCount > 8) // TODO: constant
{
LCR_LOG1("car not OK for some time, fixing");
for (int i = 0; i < LCR_CAR_JOINTS; ++i)
{
if (LCR_racing.carNotOKCount < 30) // TODO: const
{
// for a while try to smoothly iterate towards previous OK position
LCR_racing.carBody.joints[i].position =
TPE_vec3Plus(LCR_racing.carBody.joints[i].position,
LCR_racing.carOKPositions[i]);
LCR_racing.carBody.joints[i].position.x /= 2;
LCR_racing.carBody.joints[i].position.y /= 2;
LCR_racing.carBody.joints[i].position.z /= 2;
}
else // hard set the pos (iteration may be infinite due to sim.)
LCR_racing.carBody.joints[i].position = LCR_racing.carOKPositions[i];
for (int j = 0; j < 3; ++j) // lower speed a bit
LCR_racing.carBody.joints[i].velocity[j] =
(7 * ((int) LCR_racing.carBody.joints[i].velocity[j])) / 8;
}
}
LCR_racing.carNotOKCount += LCR_racing.carNotOKCount < 32 ? 1 : 0;
}
else
{
// car OK
// LCR_racing.carNotOKCount -= LCR_racing.carNotOKCount ? 1 : 0;
LCR_racing.carNotOKCount = 0;
for (int i = 0; i < LCR_CAR_JOINTS; ++i)
LCR_racing.carOKPositions[i] = LCR_racing.carBody.joints[i].position;
}
LCR_racing.tick++;
LCR_LOG2("racing step end");
}
void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2],
LCR_GameUnit camFov)
{
LCR_LOG2("drawing physics debug overlay");
TPE_Vec3 cPos, cRot, cView;
cPos.x = (camPos[0] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT;
@ -504,7 +730,7 @@ void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2],
cView.z = (camFov * TPE_F) / LCR_GAME_UNIT;
TPE_worldDebugDraw(&(LCR_racing.physicsWorld),_LCR_drawPhysicsDebugPixel,
cPos,cRot,cView,16,LCR_PHYSICS_UNIT / 4);
cPos,cRot,cView,16,LCR_PHYSICS_UNIT / 4,LCR_racing.tick * 4);
}
#endif // guard

View file

@ -16,7 +16,8 @@
/// Renderer specific unit, length of one map square.
#define LCR_RENDERER_UNIT (S3L_F / 2)
// ^ just S3L_F leaves some tris bugging
// NOTE: ^ S3L_F sometimes makes some triangles bug, S3L_F/2 seems to fix it
// but it's more jerky, maybe try to apply anti-overflow in S3L?
#define LCR_RENDERER_CHUNK_RESOLUTION 4 // do not change
#define LCR_RENDERER_LOD_BLOCKS 64 // do not change
@ -30,6 +31,10 @@
#define LCR_RENDERER_MODEL_COUNT 10
#define LCR_RENDERER_CAR_SCALE (LCR_RENDERER_UNIT / 4)
/** For some reason the map model is a bit misaligned with physics world, this
kinda hotfixes it -- later try to discover source of this bug. TODO */
#define _LCR_MAP_MODEL_SCALE 1034
struct
{
S3L_Scene scene;
@ -86,6 +91,8 @@ struct
void LCR_rendererSetCarTransform(LCR_GameUnit position[3],
LCR_GameUnit rotation[3])
{
LCR_LOG2("setting car transform");
LCR_renderer.carModel->transform.translation.x =
(position[0] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT;
LCR_renderer.carModel->transform.translation.y =
@ -266,7 +273,7 @@ S3L_Index _LCR_rendererAddMapVert(S3L_Unit x, S3L_Unit y, S3L_Unit z)
return LCR_renderer.mapModel.vertexCount - 1;
}
LCR_log("couldn't add map vertex!");
LCR_LOG0("couldn't add map vertex!");
return 0;
}
@ -474,7 +481,7 @@ uint8_t _LCR_rendererCheckMapTriCover(const S3L_Index *t1,
*/
void _LCR_cullHiddenMapTris(void)
{
LCR_log("culling invisible triangles");
LCR_LOG1("culling invisible triangles");
int n = 0; // number of removed elements
int i = 0;
@ -562,7 +569,7 @@ void _LCR_cullHiddenMapTris(void)
void _LCR_makeMapChunks(void)
{
LCR_log("making map chunks");
LCR_LOG1("making map chunks");
S3L_Index start = 0;
@ -607,7 +614,7 @@ void _LCR_makeMapChunks(void)
*/
uint8_t _LCR_buildMapModel(void)
{
LCR_log("building map model");
LCR_LOG1("building map model");
uint8_t blockShapeBytes[LCR_MAP_BLOCK_SHAPE_MAX_BYTES];
uint8_t blockShapeByteCount;
@ -615,6 +622,13 @@ uint8_t _LCR_buildMapModel(void)
S3L_model3DInit(LCR_renderer.mapVerts,0,LCR_renderer.mapTris,0,
&LCR_renderer.mapModel);
LCR_renderer.mapModel.transform.scale.x =
(_LCR_MAP_MODEL_SCALE * S3L_F) / 1024;
LCR_renderer.mapModel.transform.scale.y
= LCR_renderer.mapModel.transform.scale.x;
LCR_renderer.mapModel.transform.scale.z
= LCR_renderer.mapModel.transform.scale.x;
for (int j = 0; j < LCR_currentMap.blockCount; ++j)
{
if ((j + 1) % LCR_SETTING_TRIANGLE_CULLING_PERIOD == 0)
@ -714,7 +728,8 @@ uint8_t _LCR_buildMapModel(void)
}
}
_LCR_rendererAddMapTri(triIndices[0],triIndices[1],triIndices[2],triData);
_LCR_rendererAddMapTri(triIndices[0],triIndices[1],triIndices[2],
triData);
}
vi = 0;
@ -726,14 +741,14 @@ uint8_t _LCR_buildMapModel(void)
_LCR_cullHiddenMapTris();
LCR_log("map model built");
LCR_LOG1("map model built");
return 1;
}
void _LCR_rendererComputeLOD(void)
{
LCR_log("computing LOD");
LCR_LOG1("computing LOD");
for (int i = 0; i < LCR_RENDERER_LOD_BLOCKS; ++i)
LCR_renderer.gridOfLODs[i] = 0;
@ -754,7 +769,7 @@ void _LCR_rendererComputeLOD(void)
uint8_t LCR_rendererInit(void)
{
LCR_log("initializing renderer");
LCR_LOG0("initializing renderer");
LCR_renderer.frame = 0;
@ -821,6 +836,8 @@ LCR_renderer.ghostModel->transform.translation.x -= LCR_GAME_UNIT / 4;
LCR_renderer.wheelSteer = 0;
#endif
LCR_LOG2("initializing 3D scene");
S3L_sceneInit(
LCR_renderer.models,LCR_RENDERER_MODEL_COUNT,&LCR_renderer.scene);
@ -851,6 +868,8 @@ void LCR_rendererGetCameraTransform(LCR_GameUnit position[3],
void LCR_rendererMoveCamera(LCR_GameUnit forwRightUpOffset[3],
LCR_GameUnit yawPitchOffset[2])
{
LCR_LOG2("moving camera");
S3L_Vec4 f, r, u;
S3L_rotationToDirections(LCR_renderer.scene.camera.transform.rotation,
@ -898,7 +917,7 @@ void LCR_rendererDrawRect(int x, int y, unsigned int w, unsigned int h,
if (x < 0)
{
if (-1 * x > ((int) w))
if (-1 * x >= ((int) w))
return;
w += x;
@ -917,7 +936,7 @@ void LCR_rendererDrawRect(int x, int y, unsigned int w, unsigned int h,
y = 0;
}
if (y + h > LCR_EFFECTIVE_RESOLUTION_X)
if (y + h > LCR_EFFECTIVE_RESOLUTION_Y)
h = LCR_EFFECTIVE_RESOLUTION_Y - y;
unsigned long index = y * LCR_EFFECTIVE_RESOLUTION_X + x;
@ -950,6 +969,8 @@ void LCR_rendererDrawRect(int x, int y, unsigned int w, unsigned int h,
void _LCR_rendererDrawLODBlock(int blockX, int blockY, int blockZ, unsigned int size,
uint16_t color, uint8_t variability)
{
LCR_LOG2("drawing LOD block");
S3L_Vec4 p, r;
p.x = (blockX - LCR_MAP_SIZE_BLOCKS / 2) * LCR_RENDERER_UNIT
@ -994,6 +1015,8 @@ void _LCR_rendererDrawLODBlock(int blockX, int blockY, int blockZ, unsigned int
*/
void LCR_rendererDrawSky(int sky, S3L_Unit offsetH, S3L_Unit offsetV)
{
LCR_LOG2("drawing sky");
int anchorPoint[2], y;
unsigned long pixelIndex;
unsigned int topColor, bottomColor;
@ -1183,6 +1206,8 @@ S3L_Unit _LCR_rendererSmoothRot(S3L_Unit angleOld, S3L_Unit angleNew,
*/
void _LCR_rendererLoadMapChunks(void)
{
LCR_LOG2("loading map chunks");
int8_t camChunk[3], chunkOffsets[3];
S3L_Vec4 cp = LCR_renderer.scene.camera.transform.translation;
S3L_Vec4 cf;
@ -1223,6 +1248,8 @@ void _LCR_rendererLoadMapChunks(void)
*/
void LCR_rendererDrawLOD(void)
{
LCR_LOG2("drawing LOD");
#if LCR_SETTING_LOD_DISTANCE < 64
int variability = 0;
@ -1254,6 +1281,8 @@ void LCR_rendererDrawLOD(void)
void LCR_drawLevelFloor(void)
{
LCR_LOG2("drawing floor");
#if LCR_SETTING_FLOOR_PARTICLE_SIZE != 0
#define _STEP ((LCR_MAP_SIZE_BLOCKS * LCR_RENDERER_UNIT) / LCR_SETTING_FLOOR_PARTICLE_RESOLUTION)
@ -1289,6 +1318,8 @@ void LCR_drawLevelFloor(void)
#if LCR_ANIMATE_CAR
void _LCR_rendererAnimateCar(void)
{
LCR_LOG2("animating car");
for (int i = LCR_renderer.frame % LCR_SETTING_CAR_ANIMATION_SUBDIVIDE;
i < LCR_CAR_VERTEX_COUNT; i += LCR_SETTING_CAR_ANIMATION_SUBDIVIDE)
{
@ -1338,6 +1369,8 @@ void _LCR_rendererAnimateCar(void)
void LCR_rendererCameraFollow(void)
{
LCR_LOG2("following camera");
S3L_Transform3D transPrev = LCR_renderer.scene.camera.transform;
LCR_renderer.scene.camera.transform.translation.y =
@ -1414,6 +1447,8 @@ void LCR_rendererSetWheelState(LCR_GameUnit rotation, LCR_GameUnit steer)
void LCR_rendererDraw(void)
{
LCR_LOG2("rendering frame (start)");
// first make sure rotations are in correct range:
LCR_renderer.scene.camera.transform.rotation.y = S3L_wrap(
LCR_renderer.scene.camera.transform.rotation.y, S3L_F);
@ -1437,9 +1472,13 @@ void LCR_rendererDraw(void)
LCR_drawLevelFloor();
LCR_rendererDrawLOD();
LCR_LOG2("gonna render 3D scene");
S3L_drawScene(LCR_renderer.scene);
LCR_LOG2("rendering 3D scene done");
LCR_renderer.frame++;
LCR_LOG2("rendering frame (end)");
}
#endif // guard

View file

@ -131,4 +131,11 @@
#define LCR_SETTING_SMOOTH_ANIMATIONS 1
#endif
#ifndef LCR_SETTING_LOG_LEVEL
/** How detailed the console logs should be. 0 turns off logging, 1 means
normal, 2 more detailed etc. Setting high log level may result in spam and
slower game, but is useful for debugging. */
#define LCR_SETTING_LOG_LEVEL 1
#endif
#endif // guard

View file

@ -252,6 +252,9 @@ typedef struct
energy. */
#define TPE_BODY_FLAG_NO_BSPHERE 64 /**< Stops quick bounding sphere checks
against environment. */
#define TPE_BODY_FLAG_UNRESOLVED 128 /**< Set automatically for bodies whose
collision with environment failed
to be resolved. */
/** Function used for defining static environment, working similarly to an SDF
(signed distance function). The parameters are: 3D point P, max distance D.
@ -539,7 +542,7 @@ TPE_Vec3 TPE_bodyGetCenterOfMass(const TPE_Body *body);
e.g. 16). */
void TPE_worldDebugDraw(TPE_World *world, TPE_DebugDrawFunction drawFunc,
TPE_Vec3 camPos, TPE_Vec3 camRot, TPE_Vec3 camView, uint16_t envGridRes,
TPE_Unit envGridSize);
TPE_Unit envGridSize, TPE_Unit offset);
#define TPE_DEBUG_COLOR_CONNECTION 0
#define TPE_DEBUG_COLOR_JOINT 1
@ -592,7 +595,7 @@ TPE_Vec3 TPE_envLineSegment(TPE_Vec3 point, TPE_Vec3 a, TPE_Vec3 b);
TPE_Vec3 TPE_envHeightmap(TPE_Vec3 point, TPE_Vec3 center, TPE_Unit gridSize,
TPE_Unit (*heightFunction)(int32_t x, int32_t y), TPE_Unit maxDist);
/** Environment function for triagnular prism, e.g. for ramps. The sides array
/** Environment function for triangular prism, e.g. for ramps. The sides array
contains three 2D coordinates of points of the triangle in given plane with
respect to the center. WARNING: the points must be specified in counter
clowckwise direction! The direction var specified axis direction (0, 1 or
@ -637,8 +640,7 @@ static inline TPE_Unit TPE_nonZero(TPE_Unit x)
static inline TPE_Unit TPE_connectionTension(TPE_Unit length,
TPE_Unit desiredLength)
{
return (length * TPE_F) / desiredLength
- TPE_F;
return (length * TPE_F) / desiredLength - TPE_F;
}
TPE_Joint TPE_joint(TPE_Vec3 position, TPE_Unit size)
@ -1913,6 +1915,8 @@ uint8_t TPE_bodyEnvironmentResolveCollision(TPE_Body *body,
TPE_Vec3 c;
TPE_Unit d;
body->flags &= ~TPE_BODY_FLAG_UNRESOLVED;
if (!(body->flags & TPE_BODY_FLAG_NO_BSPHERE))
{
TPE_bodyGetFastBSphere(body,&c,&d);
@ -1938,6 +1942,9 @@ uint8_t TPE_bodyEnvironmentResolveCollision(TPE_Body *body,
{
collision = 1;
if (r == 2)
body->flags |= TPE_BODY_FLAG_UNRESOLVED;
if (body->flags & TPE_BODY_FLAG_NONROTATING)
_TPE_bodyNonrotatingJointCollided(body,i,previousPos,r == 1);
}
@ -2079,7 +2086,7 @@ void _TPE_drawDebugPixel(
void TPE_worldDebugDraw(TPE_World *world, TPE_DebugDrawFunction drawFunc,
TPE_Vec3 camPos, TPE_Vec3 camRot, TPE_Vec3 camView, uint16_t envGridRes,
TPE_Unit envGridSize)
TPE_Unit envGridSize, TPE_Unit offset)
{
#define Z_LIMIT 250
if (world->environmentFunction != 0)
@ -2092,6 +2099,8 @@ void TPE_worldDebugDraw(TPE_World *world, TPE_DebugDrawFunction drawFunc,
TPE_Vec3 center;
offset %= envGridSize;
if (envGridRes != 0)
{
center = TPE_vec3(0,TPE_sin(camRot.x),TPE_cos(camRot.x));
@ -2101,9 +2110,9 @@ void TPE_worldDebugDraw(TPE_World *world, TPE_DebugDrawFunction drawFunc,
center = TPE_vec3Times(center,gridHalfSize);
center = TPE_vec3Plus(camPos,center);
center.x = (center.x / envGridSize) * envGridSize;
center.y = (center.y / envGridSize) * envGridSize;
center.z = (center.z / envGridSize) * envGridSize;
center.x = (center.x / envGridSize) * envGridSize + offset;
center.y = (center.y / envGridSize) * envGridSize + offset;
center.z = (center.z / envGridSize) * envGridSize + offset;
}
testPoint.y = center.y - gridHalfSize;