mirror of
https://gitlab.com/drummyfish/anarch.git
synced 2024-08-13 15:53:48 -04:00
Init
This commit is contained in:
commit
542d043057
42
assets.h
Normal file
42
assets.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef _SFG_RESOURCES_H
|
||||
#define _SFG_RESOURCES_H
|
||||
|
||||
#define SFG_TEXTURE_SIZE 32
|
||||
|
||||
static inline uint8_t SFG_getTexel(uint8_t *texture, uint8_t x, uint8_t y)
|
||||
{
|
||||
return texture[(y & 0x1f) * SFG_TEXTURE_SIZE + (x & 0x1f)];
|
||||
}
|
||||
|
||||
const uint8_t SFG_textureWall1[SFG_TEXTURE_SIZE * SFG_TEXTURE_SIZE] = {
|
||||
5,4,4,5,59,2,5,5,4,66,45,5,4,4,4,4,4,4,2,5,4,44,4,4,4,4,3,3,2,44,4,4,4,4,4,51,
|
||||
67,8,5,86,3,2,4,5,4,4,4,4,4,4,2,4,5,4,4,5,4,5,4,50,3,60,44,5,131,131,131,3,2,66,
|
||||
60,4,2,2,3,3,4,3,4,3,4,3,49,2,2,5,4,3,51,3,131,2,50,66,2,131,4,4,4,4,66,3,3,3,
|
||||
81,81,3,4,3,59,2,66,82,81,2,66,218,66,138,131,2,2,56,3,4,4,4,4,44,4,4,4,2,6,6,6,
|
||||
5,6,4,4,6,6,5,6,5,6,6,6,6,6,5,6,5,6,6,3,4,4,4,5,4,4,4,4,3,6,5,5,5,4,4,5,5,4,5,4,
|
||||
5,5,4,5,5,5,5,5,5,5,5,3,4,4,4,132,132,4,44,4,3,6,5,4,4,4,4,5,5,4,4,5,4,5,4,5,4,
|
||||
5,4,5,4,5,5,2,5,4,4,4,4,4,4,3,3,6,5,5,5,4,5,5,5,5,5,5,44,5,44,5,5,5,5,5,5,5,5,
|
||||
51,4,4,4,4,3,4,4,3,3,6,5,5,5,5,5,5,5,5,5,5,4,5,5,5,5,45,4,5,4,5,6,3,132,4,4,4,
|
||||
66,66,2,1,3,6,4,4,5,5,5,5,5,5,5,5,4,5,4,5,4,5,5,5,4,5,5,51,4,139,138,131,3,2,2,
|
||||
2,3,6,5,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,45,5,5,5,3,2,3,4,3,5,4,5,3,3,6,5,4,5,5,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,3,4,4,5,4,4,4,4,3,5,4,5,5,5,5,5,5,5,5,5,5,5,
|
||||
5,5,5,5,5,4,5,5,5,131,3,4,4,4,4,4,4,3,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,5,
|
||||
5,5,2,3,4,4,4,4,5,4,50,3,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,5,5,3,3,5,4,5,
|
||||
4,5,4,3,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,2,3,4,4,5,4,4,4,137,3,6,5,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,2,3,4,4,4,5,4,4,0,3,6,5,28,5,5,5,5,5,5,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,6,3,3,5,5,4,3,3,3,1,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
5,5,4,5,5,3,50,3,3,51,132,4,3,50,3,6,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
3,1,3,3,4,4,4,4,3,3,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,28,5,4,5,4,3,5,4,4,5,4,
|
||||
5,3,3,6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,3,2,4,4,4,4,5,5,44,3,6,4,5,5,
|
||||
5,5,5,5,5,4,5,5,4,5,5,5,5,5,4,5,4,5,3,3,5,4,4,44,5,4,4,3,5,5,4,5,5,5,6,4,5,5,5,
|
||||
5,28,5,5,5,4,4,5,4,5,5,4,3,4,5,5,4,4,4,4,3,6,5,5,5,4,5,20,5,5,5,4,5,5,5,5,5,5,5,
|
||||
28,5,4,5,3,3,45,4,5,4,5,5,3,3,6,5,5,5,5,5,5,5,5,5,5,5,5,5,6,5,5,5,4,5,5,6,4,3,4,
|
||||
5,5,3,3,3,131,59,4,3,4,3,4,3,4,4,3,4,26,3,3,26,4,26,3,4,3,2,2,131,50,3,4,4,51,4,
|
||||
4,4,4,2,50,138,217,2,2,2,2,2,2,138,3,3,2,2,81,131,3,2,3,3,4,3,4,2,131,3,5,5,4,5,
|
||||
5,2,3,4,4,4,81,4,4,4,4,4,4,4,4,2,4,4,4,4,4,4,4,4,5,2,4,5,5,44,44,4,5,4,3,5,5,4,
|
||||
66,4,4,3,4,4,4,4,3,4,4,4,4,4,4,4,4,4,86,2,4,45,4,4,4,4,4,4,83,5,5,4,49,4,4,4,3,
|
||||
4,4,4,3,3,4,4,4,4,3,4,4,3,5,3,5,4,61,4,132,4,4,4,2,5,85,4,2,4,4,4,4,4,44,4,3,3,
|
||||
5,4,4,4,4,4,4,3,6,66,4,4,4
|
||||
};
|
||||
|
||||
#endif // guard
|
155
assets/img2array.py
Normal file
155
assets/img2array.py
Normal file
@ -0,0 +1,155 @@
|
||||
# Python tool to convert an image to C array for small3dlib.
|
||||
#
|
||||
# by drummyfish
|
||||
# released under CC0 1.0.
|
||||
|
||||
import sys
|
||||
from PIL import Image
|
||||
|
||||
def printHelp():
|
||||
print("Convert image to C array for small3dlib.")
|
||||
print("usage:\n")
|
||||
print(" python img2array.py [-xW -yH -h -nS -pT -5] file\n")
|
||||
print(" -xW set width of the output to W pixels")
|
||||
print(" -yH set height of the output to H pixels")
|
||||
print(" -h include header guards (for texture per file)")
|
||||
print(" -nS use the name S for the texture (defaut: \"texture\")")
|
||||
print(" -pT use palette from file T and indexed colors (otherwise direct colors)")
|
||||
print(" -5 use 565 format instead of RGB8")
|
||||
print("");
|
||||
print("by Miloslav \"drummyfish\" Ciz")
|
||||
print("released under CC0 1.0")
|
||||
|
||||
def rgbTo565(rgb):
|
||||
return ((rgb[0] >> 3) << 11) | ((rgb[1] >> 2) << 5) | ((rgb[2] >> 3))
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
printHelp()
|
||||
quit()
|
||||
|
||||
FILENAME = ""
|
||||
PALETTE = ""
|
||||
USE_PALETTE = False
|
||||
NAME = "texture"
|
||||
GUARDS = False
|
||||
OUT_WIDTH = 64
|
||||
OUT_HEIGHT = 64
|
||||
USE_565 = False
|
||||
|
||||
for s in sys.argv:
|
||||
if s [:2] == "-x":
|
||||
OUT_WIDTH = int(s[2:])
|
||||
elif s [:2] == "-y":
|
||||
OUT_HEIGHT = int(s[2:])
|
||||
elif s == "-h":
|
||||
GUARDS = True
|
||||
elif s[:2] == "-n":
|
||||
NAME = s[2:]
|
||||
elif s[:2] == "-5":
|
||||
USE_565 = True
|
||||
elif s[:2] == "-p":
|
||||
PALETTE = s[2:]
|
||||
USE_PALETTE = True
|
||||
else:
|
||||
FILENAME = s
|
||||
|
||||
imageArray = []
|
||||
paletteColors = []
|
||||
paletteArray = []
|
||||
|
||||
image = Image.open(FILENAME).convert("RGB")
|
||||
pixels = image.load()
|
||||
|
||||
if USE_PALETTE > 0:
|
||||
palette = Image.open(PALETTE).convert("RGB")
|
||||
pixelsPal = palette.load()
|
||||
|
||||
for y in range(palette.size[1]):
|
||||
for x in range(palette.size[0]):
|
||||
c = pixelsPal[x,y]
|
||||
paletteColors.append(c)
|
||||
|
||||
if USE_565:
|
||||
paletteArray.append(rgbTo565(c))
|
||||
else:
|
||||
paletteArray.append(c[0])
|
||||
paletteArray.append(c[1])
|
||||
paletteArray.append(c[2])
|
||||
|
||||
image2 = Image.new("RGB",(OUT_WIDTH,OUT_HEIGHT),color="white")
|
||||
pixels2 = image2.load()
|
||||
|
||||
for y in range(OUT_HEIGHT):
|
||||
for x in range(OUT_WIDTH):
|
||||
coord = (
|
||||
int(x / float(OUT_WIDTH) * image.size[0]),
|
||||
int(y / float(OUT_HEIGHT) * image.size[1]))
|
||||
|
||||
pixel = pixels[coord]
|
||||
|
||||
if USE_PALETTE:
|
||||
closestIndex = 0
|
||||
closestDiff = 1024
|
||||
|
||||
# find the index of the closest color:
|
||||
|
||||
for i in range(len(paletteColors)):
|
||||
c = paletteColors[i]
|
||||
diff = abs(pixel[0] - c[0]) + abs(pixel[1] - c[1]) + abs(pixel[2] - c[2])
|
||||
|
||||
if diff < closestDiff:
|
||||
closestIndex = i
|
||||
closestDiff = diff
|
||||
|
||||
imageArray.append(closestIndex)
|
||||
pixels2[x,y] = paletteColors[closestIndex]
|
||||
else:
|
||||
if USE_565:
|
||||
imageArray.append(rgbTo565(pixel))
|
||||
else:
|
||||
imageArray.append(pixel[0])
|
||||
imageArray.append(pixel[1])
|
||||
imageArray.append(pixel[2])
|
||||
|
||||
pixels2[x,y] = pixel
|
||||
|
||||
#-----------------------
|
||||
|
||||
def printArray(array, name, sizeString, dataType="const uint8_t"):
|
||||
print(dataType + " " + name + "[" + sizeString + "] = {")
|
||||
arrayString = ""
|
||||
|
||||
lineLen = 0
|
||||
|
||||
for v in array:
|
||||
item = str(v) + ","
|
||||
|
||||
lineLen += len(item)
|
||||
|
||||
if lineLen > 80:
|
||||
arrayString += "\n"
|
||||
lineLen = len(item)
|
||||
|
||||
arrayString += item
|
||||
|
||||
print(arrayString[:-1])
|
||||
print("}; // " + name)
|
||||
|
||||
if GUARDS:
|
||||
print("#ifndef " + NAME.upper() + "_TEXTURE_H")
|
||||
print("#define " + NAME.upper() + "_TEXTURE_H\n")
|
||||
|
||||
if USE_PALETTE:
|
||||
printArray(paletteArray,NAME + "Palette",str(len(paletteArray)),"const uint16_t" if USE_565 else "const uint8_t")
|
||||
print("")
|
||||
|
||||
print("#define " + NAME.upper() + "_TEXTURE_WIDTH " + str(OUT_WIDTH))
|
||||
print("#define " + NAME.upper() + "_TEXTURE_HEIGHT " + str(OUT_HEIGHT))
|
||||
print("")
|
||||
|
||||
printArray(imageArray,NAME + "Texture",str(len(imageArray)))
|
||||
|
||||
if GUARDS:
|
||||
print("\n#endif // guard")
|
||||
|
||||
image2.save(NAME + "_preview.png")
|
BIN
assets/palette565.png
Normal file
BIN
assets/palette565.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 414 B |
BIN
assets/wall_texture1.png
Normal file
BIN
assets/wall_texture1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
14
constants.h
Normal file
14
constants.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _SFG_CONSTANTS_H
|
||||
#define _SFG_CONSTANTS_H
|
||||
|
||||
/**
|
||||
How quickly player turns left/right, in degrees per second.
|
||||
*/
|
||||
#define SFG_PLAYER_TURN_SPEED 180
|
||||
|
||||
/**
|
||||
How quickly player moves, in squares per second.
|
||||
*/
|
||||
#define SFG_PLAYER_MOVE_SPEED 5
|
||||
|
||||
#endif // guard
|
167
levels.h
Normal file
167
levels.h
Normal file
@ -0,0 +1,167 @@
|
||||
#ifndef _SFG_LEVELS_H
|
||||
#define _SFG_LEVELS_H
|
||||
|
||||
#define SFG_MAP_SIZE 64
|
||||
#define SFG_TILE_DICTIONARY_SIZE 64
|
||||
|
||||
typedef uint16_t SFG_TileDefinition;
|
||||
/**<
|
||||
Defines a single game map tile. The format is following:
|
||||
|
||||
MSB aaabbbbb cccddddd LSB
|
||||
|
||||
aaa: ceiling texture index (from texture available on the map)
|
||||
bbbb: ceiling height (1111 meaning no ceiling) ABOVE the floor
|
||||
ccc: floor texture index
|
||||
dddd: floor height
|
||||
*/
|
||||
|
||||
typedef SFG_TileDefinition SFG_TileDictionary[SFG_TILE_DICTIONARY_SIZE];
|
||||
|
||||
/// helper macros for SFG_TileDefinition
|
||||
#define SFG_TD(floorH, ceilH, floorT, ceilT)\
|
||||
((floorH & 0x001f) |\
|
||||
((floorT & 0x0007) << 5) |\
|
||||
((ceilH & 0x001f) << 8) |\
|
||||
((ceilT & 0x0007) << 13))
|
||||
|
||||
#define SFG_TILE_FLOOR_HEIGHT(tile) (tile & 0x1f)
|
||||
|
||||
typedef uint8_t SFG_MapArray[SFG_MAP_SIZE * SFG_MAP_SIZE];
|
||||
/**<
|
||||
Game map represented as a 2D array. Array item has this format:
|
||||
|
||||
MSB aabbbbbb LSB
|
||||
|
||||
aa: type of square, possible values:
|
||||
00: normal
|
||||
01: moving floor (elevator), moves from height 0 to floor height
|
||||
10: moving ceiling, moves from ceiling height to floor height
|
||||
11: door
|
||||
bbbbbb: index into tile dictionary
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SFG_TileDictionary tileDictionary;
|
||||
SFG_MapArray mapArray;
|
||||
} SFG_Map;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
SFG_Map map;
|
||||
} SFG_Level;
|
||||
|
||||
static inline SFG_TileDefinition SFG_getMapTile(SFG_Map *map, int16_t x, int16_t y)
|
||||
{
|
||||
if (x < 0 || x >= SFG_MAP_SIZE || y < 0 || y >= SFG_MAP_SIZE)
|
||||
return SFG_TD(10,10,0,0);
|
||||
|
||||
return map->tileDictionary[map->mapArray[y * SFG_MAP_SIZE + x] & 0x3f];
|
||||
}
|
||||
|
||||
static inline uint8_t SFG_getMapTileProperties(SFG_Map *map, int16_t x, int16_t y)
|
||||
{
|
||||
if (x < 0 || x >= SFG_MAP_SIZE || y < 0 || y >= SFG_MAP_SIZE)
|
||||
return 0;
|
||||
|
||||
return map->mapArray[y * SFG_MAP_SIZE + x] & 0xc0;
|
||||
}
|
||||
|
||||
static const SFG_Level SFG_level0 =
|
||||
{
|
||||
.map =
|
||||
{
|
||||
.tileDictionary =
|
||||
{
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(5 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 0
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 4
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 8
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 12
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 16
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 20
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 24
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 28
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 32
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 36
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 40
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 44
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 48
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 52
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 56
|
||||
SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0),SFG_TD(0 ,0 ,0,0), // 60
|
||||
},
|
||||
|
||||
.mapArray =
|
||||
{
|
||||
#define o 0
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,1 ,1 ,1 ,1 ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,o ,
|
||||
#undef o
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // guard
|
207
main.c
Executable file
207
main.c
Executable file
@ -0,0 +1,207 @@
|
||||
#include <stdint.h>
|
||||
#include "constants.h"
|
||||
#include "levels.h"
|
||||
#include "assets.h"
|
||||
|
||||
#define SFG_KEY_UP 0
|
||||
#define SFG_KEY_RIGHT 1
|
||||
#define SFG_KEY_DOWN 2
|
||||
#define SFG_KEY_LEFT 3
|
||||
#define SFG_KEY_A 4
|
||||
#define SFG_KEY_B 5
|
||||
#define SFG_KEY_C 6
|
||||
|
||||
/* ============================= PORTING =================================== */
|
||||
|
||||
/* When porting, define the following in your specific platform_*.h. Also you
|
||||
have to call SFG_mainLoopBody() in the platform's main loop and SFG_init()
|
||||
in the platform initialization. */
|
||||
|
||||
// SFG_RESOLUTION_X #define this to screen width in pixels
|
||||
// SFG_RESOLUTION_Y #define this to screen height in pixels
|
||||
// SFG_FPS #define this to desired FPS
|
||||
|
||||
/** Return 1 (0) if given key is pressed (not pressed). */
|
||||
int8_t SFG_keyPressed(uint8_t key);
|
||||
|
||||
/** Return time in ms sice program start. */
|
||||
uint32_t SFG_getTimeMs();
|
||||
|
||||
/** Sleep (yield CPU) for specified amount of ms. This is used to relieve CPU
|
||||
usage. If your platform doesn't need this or handles it in other way, this
|
||||
function can do nothing. */
|
||||
void SFG_sleepMs(uint16_t timeMs);
|
||||
|
||||
/** Set specified screen pixel. The function doesn't have to check whether
|
||||
the coordinates are within screen. */
|
||||
static inline void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex);
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
/**
|
||||
Game main loop body, call this inside the platform's specific main loop.
|
||||
*/
|
||||
void SFG_mainLoopBody();
|
||||
|
||||
/**
|
||||
Initializes the whole program, call this in the platform initialization.
|
||||
*/
|
||||
void SFG_init();
|
||||
|
||||
#include "platform_sdl.h"
|
||||
|
||||
#define SFG_MS_PER_FRAME (1000 / SFG_FPS) // ms per frame with target FPS
|
||||
|
||||
#define RCL_PIXEL_FUNCTION SFG_pixelFunc
|
||||
#define RCL_TEXTURE_VERTICAL_STRETCH 0
|
||||
|
||||
#include "raycastlib.h"
|
||||
|
||||
RCL_Camera SFG_camera;
|
||||
RCL_RayConstraints SFG_rayConstraints;
|
||||
|
||||
void SFG_pixelFunc(RCL_PixelInfo *pixel)
|
||||
{
|
||||
uint8_t color;
|
||||
uint8_t shadow = 0;
|
||||
|
||||
if (pixel->isWall)
|
||||
{
|
||||
color = SFG_getTexel(SFG_textureWall1,pixel->texCoords.x / 16,pixel->texCoords.y / 16);
|
||||
shadow = pixel->hit.direction >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = pixel->isFloor ? 20 : 50;
|
||||
}
|
||||
|
||||
shadow += pixel->depth / (RCL_UNITS_PER_SQUARE * 2);
|
||||
|
||||
color = palette_minusValue(color,shadow);
|
||||
|
||||
SFG_setPixel(pixel->position.x,pixel->position.y,color);
|
||||
}
|
||||
|
||||
RCL_Unit SFG_textureAt(int16_t x, int16_t y)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
RCL_Unit SFG_floorHeightAt(int16_t x, int16_t y)
|
||||
{
|
||||
SFG_TileDefinition tile = SFG_getMapTile(&SFG_level0,x,y);
|
||||
|
||||
return SFG_TILE_FLOOR_HEIGHT(tile) * (RCL_UNITS_PER_SQUARE / 2);
|
||||
}
|
||||
|
||||
RCL_Unit SFG_ceilingHeightAt(int16_t x, int16_t y)
|
||||
{
|
||||
return RCL_UNITS_PER_SQUARE * 8;
|
||||
}
|
||||
|
||||
uint32_t SFG_frame;
|
||||
uint32_t SFG_lastFrameTimeMs;
|
||||
|
||||
void SFG_init()
|
||||
{
|
||||
SFG_frame = 0;
|
||||
SFG_lastFrameTimeMs = 0;
|
||||
|
||||
RCL_initCamera(&SFG_camera);
|
||||
RCL_initRayConstraints(&SFG_rayConstraints);
|
||||
|
||||
SFG_camera.resolution.x = SFG_RESOLUTION_X;
|
||||
SFG_camera.resolution.y = SFG_RESOLUTION_Y;
|
||||
SFG_camera.height = RCL_UNITS_PER_SQUARE;
|
||||
SFG_camera.position.x = RCL_UNITS_PER_SQUARE * 5;
|
||||
SFG_camera.position.y = RCL_UNITS_PER_SQUARE * 5;
|
||||
|
||||
SFG_rayConstraints.maxHits = 6;
|
||||
SFG_rayConstraints.maxSteps = 32;
|
||||
}
|
||||
|
||||
#define SFG_PLAYER_TURN_UNITS_PER_FRAME\
|
||||
((SFG_PLAYER_TURN_SPEED * RCL_UNITS_PER_SQUARE) / (360 * SFG_FPS))
|
||||
|
||||
#define SFG_PLAYER_MOVE_UNITS_PER_FRAME\
|
||||
((SFG_PLAYER_MOVE_SPEED * RCL_UNITS_PER_SQUARE) / SFG_FPS)
|
||||
|
||||
RCL_Vector2D playerDirection;
|
||||
|
||||
/**
|
||||
Performs one game step (logic, physics), happening SFG_MS_PER_FRAME after
|
||||
previous frame.
|
||||
*/
|
||||
void SFG_gameStep()
|
||||
{
|
||||
int8_t recomputeDirection = 0;
|
||||
|
||||
if (SFG_keyPressed(SFG_KEY_LEFT))
|
||||
{
|
||||
SFG_camera.direction -= SFG_PLAYER_TURN_UNITS_PER_FRAME;
|
||||
recomputeDirection = 1;
|
||||
}
|
||||
else if (SFG_keyPressed(SFG_KEY_RIGHT))
|
||||
{
|
||||
SFG_camera.direction += SFG_PLAYER_TURN_UNITS_PER_FRAME;
|
||||
recomputeDirection = 1;
|
||||
}
|
||||
|
||||
if (recomputeDirection)
|
||||
{
|
||||
playerDirection = RCL_angleToDirection(SFG_camera.direction);
|
||||
|
||||
playerDirection.x = (playerDirection.x * SFG_PLAYER_MOVE_UNITS_PER_FRAME) / RCL_UNITS_PER_SQUARE;
|
||||
playerDirection.y = (playerDirection.y * SFG_PLAYER_MOVE_UNITS_PER_FRAME) / RCL_UNITS_PER_SQUARE;
|
||||
}
|
||||
|
||||
if (SFG_keyPressed(SFG_KEY_UP))
|
||||
{
|
||||
SFG_camera.position.x += playerDirection.x;
|
||||
SFG_camera.position.y += playerDirection.y;
|
||||
}
|
||||
else if (SFG_keyPressed(SFG_KEY_DOWN))
|
||||
{
|
||||
SFG_camera.position.x -= playerDirection.x;
|
||||
SFG_camera.position.y -= playerDirection.y;
|
||||
}
|
||||
|
||||
if (SFG_keyPressed(SFG_KEY_A))
|
||||
SFG_camera.height += SFG_PLAYER_MOVE_UNITS_PER_FRAME;
|
||||
else if (SFG_keyPressed(SFG_KEY_B))
|
||||
SFG_camera.height -= SFG_PLAYER_MOVE_UNITS_PER_FRAME;
|
||||
}
|
||||
|
||||
void SFG_mainLoopBody()
|
||||
{
|
||||
/* standard deterministic game loop, independed on actuall achieved FPS,
|
||||
each game logic (physics) frame is performed with the SFG_MS_PER_FRAME
|
||||
delta time. */
|
||||
|
||||
uint32_t timeNow = SFG_getTimeMs();
|
||||
uint16_t timeSinceLastFrame = timeNow - SFG_lastFrameTimeMs;
|
||||
|
||||
if (timeSinceLastFrame >= SFG_MS_PER_FRAME)
|
||||
{
|
||||
// perform game logic (physics), for each frame
|
||||
while (timeSinceLastFrame >= SFG_MS_PER_FRAME)
|
||||
{
|
||||
SFG_gameStep();
|
||||
|
||||
timeSinceLastFrame -= SFG_MS_PER_FRAME;
|
||||
|
||||
SFG_frame++;
|
||||
}
|
||||
|
||||
// render noly once
|
||||
RCL_renderComplex(SFG_camera,SFG_floorHeightAt,SFG_ceilingHeightAt,SFG_textureAt,SFG_rayConstraints);
|
||||
|
||||
SFG_lastFrameTimeMs = timeNow;
|
||||
}
|
||||
|
||||
uint32_t timeNextFrame = timeNow + SFG_MS_PER_FRAME;
|
||||
timeNow = SFG_getTimeMs();
|
||||
|
||||
if (timeNextFrame > timeNow)
|
||||
SFG_sleepMs((timeNextFrame - timeNow) / 2); // wait, relieve CPU
|
||||
}
|
66
palette.h
Normal file
66
palette.h
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
General purpose HSV-based 256 color palette.
|
||||
|
||||
Define PALETTE_FORMAT_565 to use the RGB565 palette, otherwise RGB8 is used.
|
||||
|
||||
by Drummyfish, released under CC0 1.0
|
||||
*/
|
||||
|
||||
#ifndef PALETTE_256_H
|
||||
#define PALETTE_256_H
|
||||
|
||||
const uint16_t paletteRGB565[256] = {
|
||||
0, 8484, 19017, 27501, 38034, 46518, 57051, 65535, 8354, 16709, 25096, 33450,
|
||||
41805, 50192, 58546, 64853, 8386, 16805, 25224, 33642, 42061, 50480, 58898,
|
||||
65269, 6402, 14853, 23304, 29706, 38157, 46608, 55058, 61429, 4354, 10757,
|
||||
17160, 23562, 29965, 36368, 42770, 49141, 4355, 10758, 17161, 21516, 27920,
|
||||
34323, 38678, 45049, 4323, 10759, 17163, 21519, 27923, 34327, 38683, 45055,
|
||||
4292, 10632, 17004, 21296, 27668, 34008, 38300, 44671, 4260, 10568, 16908,
|
||||
23216, 29524, 35864, 42172, 48479, 6308, 14664, 23052, 29360, 37716, 46104,
|
||||
54460, 60767, 8355, 16710, 25098, 33453, 41809, 50196, 58552, 64859, 8257,
|
||||
16546, 24836, 33093, 41382, 49672, 57929, 64170, 8353, 16738, 25124, 33509,
|
||||
41894, 50248, 58633, 64970, 6401, 12802, 21252, 27653, 36102, 42504, 50953,
|
||||
57322, 2305, 6658, 11012, 15365, 19718, 24072, 28425, 32746, 2306, 4612, 8967,
|
||||
11273, 13580, 17934, 20240, 22515, 2307, 4615, 8971, 11279, 13587, 17943, 20251,
|
||||
22527, 2180, 4392, 8652, 10864, 13076, 17304, 19516, 21727, 2116, 6312, 10508,
|
||||
14672, 18868, 23064, 25180, 29375, 6212, 12456, 20748, 26960, 35252, 41496,
|
||||
49756, 55999, 8258, 16549, 24840, 33099, 41390, 49681, 57940, 64183, 8192,
|
||||
16384, 24576, 32768, 40960, 49152, 57344, 63488, 8320, 16640, 24960, 33312,
|
||||
41632, 49952, 58304, 64576, 6400, 14848, 23296, 29696, 38144, 46592, 52992,
|
||||
61408, 2304, 6656, 8960, 13312, 15616, 19968, 22272, 26592, 256, 513, 769, 1026,
|
||||
1283, 1539, 1796, 2021, 258, 517, 776, 1035, 1294, 1552, 1811, 2038, 164, 360,
|
||||
556, 752, 948, 1144, 1308, 1503, 36, 104, 140, 208, 244, 312, 348, 415, 2052,
|
||||
4104, 8204, 10256, 14356, 16408, 18460, 22559, 6148, 14344, 20492, 28688, 34836,
|
||||
43032, 51228, 57375, 8194, 16388, 24582, 32777, 40971, 49165, 57359, 63505
|
||||
};
|
||||
|
||||
/** Adds value (brightness), possibly negative, to given color (represented by
|
||||
its palette index). If you know you'll only be either adding or substracting,
|
||||
use plusValue() or minusValue() functions, which should be faster. */
|
||||
static inline uint8_t palette_addValue(uint8_t color, int8_t add)
|
||||
{
|
||||
uint8_t newValue = color + add;
|
||||
|
||||
if ((newValue >> 3) == (color >> 3))
|
||||
return newValue;
|
||||
else
|
||||
return add > 0 ? (color | 0x07) : 0;
|
||||
}
|
||||
|
||||
/** Adds a positive value (brightness) to given color (represented by its
|
||||
palette index). This should be a little bit faster than addValue(). */
|
||||
static inline uint8_t palette_plusValue(uint8_t color, uint8_t plus)
|
||||
{
|
||||
uint8_t newValue = color + plus;
|
||||
return ((newValue >> 3) == (color >> 3)) ? newValue : (color | 0x07);
|
||||
}
|
||||
|
||||
/** Substracts a positive value (brightness) from given color (represented by
|
||||
its palette index). This should be a little bit faster than addValue(). */
|
||||
static inline uint8_t palette_minusValue(uint8_t color, uint8_t minus)
|
||||
{
|
||||
uint8_t newValue = color - minus;
|
||||
return ((newValue >> 3) == (color >> 3)) ? newValue : 0;
|
||||
}
|
||||
|
||||
#endif //guard
|
104
platform_sdl.h
Normal file
104
platform_sdl.h
Normal file
@ -0,0 +1,104 @@
|
||||
#ifndef _SFG_PLATFORM_H
|
||||
#define _SFG_PLATFORM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "palette.h"
|
||||
|
||||
#define SFG_RESOLUTION_X 800
|
||||
#define SFG_RESOLUTION_Y 600
|
||||
|
||||
#define SFG_FPS 60
|
||||
|
||||
const uint8_t *sdlKeyboardState;
|
||||
|
||||
uint16_t screen[SFG_RESOLUTION_X * SFG_RESOLUTION_Y]; // RGB565 format
|
||||
|
||||
void SFG_setPixel(uint16_t x, uint16_t y, uint8_t colorIndex)
|
||||
{
|
||||
screen[y * SFG_RESOLUTION_X + x] = paletteRGB565[colorIndex];
|
||||
}
|
||||
|
||||
uint32_t SFG_getTimeMs()
|
||||
{
|
||||
return SDL_GetTicks();
|
||||
}
|
||||
|
||||
void SFG_sleepMs(uint16_t timeMs)
|
||||
{
|
||||
usleep(timeMs * 1000);
|
||||
}
|
||||
|
||||
int8_t SFG_keyPressed(uint8_t key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case SFG_KEY_UP: return sdlKeyboardState[SDL_SCANCODE_UP]; break;
|
||||
case SFG_KEY_RIGHT: return sdlKeyboardState[SDL_SCANCODE_RIGHT]; break;
|
||||
case SFG_KEY_DOWN: return sdlKeyboardState[SDL_SCANCODE_DOWN]; break;
|
||||
case SFG_KEY_LEFT: return sdlKeyboardState[SDL_SCANCODE_LEFT]; break;
|
||||
case SFG_KEY_A: return sdlKeyboardState[SDL_SCANCODE_A]; break;
|
||||
case SFG_KEY_B: return sdlKeyboardState[SDL_SCANCODE_S]; break;
|
||||
case SFG_KEY_C: return sdlKeyboardState[SDL_SCANCODE_D]; break;
|
||||
default: return 0; break;
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("starting\n");
|
||||
|
||||
SFG_init();
|
||||
|
||||
printf("initializing SDL\n");
|
||||
|
||||
SDL_Window *window =
|
||||
SDL_CreateWindow("raycasting", SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED, SFG_RESOLUTION_X, SFG_RESOLUTION_Y,
|
||||
SDL_WINDOW_SHOWN);
|
||||
|
||||
SDL_Renderer *renderer = SDL_CreateRenderer(window,-1,0);
|
||||
|
||||
SDL_Texture *texture =
|
||||
SDL_CreateTexture(renderer,SDL_PIXELFORMAT_RGB565,SDL_TEXTUREACCESS_STATIC,
|
||||
SFG_RESOLUTION_X,SFG_RESOLUTION_Y);
|
||||
|
||||
SDL_Surface *screenSurface = SDL_GetWindowSurface(window);
|
||||
|
||||
SDL_Event event;
|
||||
|
||||
sdlKeyboardState = SDL_GetKeyboardState(NULL);
|
||||
|
||||
int running = 1;
|
||||
|
||||
while (running)
|
||||
{
|
||||
SDL_PumpEvents(); // updates the keyboard state
|
||||
|
||||
if (sdlKeyboardState[SDL_SCANCODE_Q])
|
||||
break;
|
||||
|
||||
SFG_mainLoopBody();
|
||||
|
||||
SDL_UpdateTexture(texture,NULL,screen,SFG_RESOLUTION_X * sizeof(uint16_t));
|
||||
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderCopy(renderer,texture,NULL,NULL);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
printf("freeing SDL\n");
|
||||
|
||||
SDL_DestroyTexture(texture);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
printf("ending\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // guard
|
1876
raycastlib.h
Normal file
1876
raycastlib.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user