Start texturing

This commit is contained in:
Miloslav Ciz 2024-07-29 17:42:40 +02:00
parent 67567e210a
commit d02b8b4ec3
5 changed files with 752 additions and 728 deletions

1165
assets.h

File diff suppressed because it is too large Load diff

View file

@ -144,7 +144,7 @@ int main(void)
for (int i = 0; i < 8; ++i)
{
unsigned int color = palette[j * 32 + i];
unsigned int color = palette[j * 8 + i];
printf("0x%02x,0x%02x,",color & 0xff,color >> 8);
}

View file

@ -1,79 +0,0 @@
import sys
from PIL import Image
def rgbTo565(rgb):
return ((rgb[0] >> 3) << 11) | ((rgb[1] >> 2) << 5) | ((rgb[2] >> 3))
def colorDist(c1,c2):
return abs((c1 & 0x1f) - (c2 & 0x1f)) + abs(((c1 >> 5) & 0x3f) - ((c2 >> 5) & 0x3f)) + abs((c1 >> 11) - (c2 >> 11))
FILENAME = sys.argv[1]
image = Image.open(FILENAME).convert("RGB")
IMG_SIZE = image.size[0]
pixels = image.load()
outArray = []
if IMG_SIZE == 64: # normal texture
for y in range(IMG_SIZE):
for x in range(IMG_SIZE):
outArray.append(rgbTo565(pixels[(x,y)]))
else: # sky texture
hist = [0 for i in range(65536)]
for y in range(IMG_SIZE):
for x in range(IMG_SIZE):
hist[rgbTo565(pixels[(x,y)])] += 1
for i in range(256): # make the palette from 256 most common colors
histMaxIndex = 0
for j in range(65536):
if hist[j] > hist[histMaxIndex]:
histMaxIndex = j
outArray.append(histMaxIndex)
hist[histMaxIndex] = -1
odd = True
for y in range(IMG_SIZE):
for x in range(IMG_SIZE):
pixel = rgbTo565(pixels[(x,y)])
closestIndex = 0
closestDist = 1000
for i in range(256):
dist = colorDist(pixel,outArray[i])
if dist < closestDist:
closestDist = dist
closestIndex = i
if closestDist == 0:
break
if odd:
outArray.append(closestIndex)
odd = False
else:
outArray[-1] = outArray[-1] | (closestIndex << 8)
odd = True
outStr = ""
for i in range(len(outArray)):
if i % 16 == 0:
outStr += "\n "
outStr += "{0:#0{1}x}".format(outArray[i],6)
if i != len(outArray) - 1:
outStr += ","
print(outStr)

15
game.h
View file

@ -112,6 +112,9 @@ void LCR_gameInit(void)
LCR_mapLoad(map1);
LCR_rendererInit();
LCR_loadImage(0);
}
void LCR_gameEnd(void)
@ -127,18 +130,8 @@ uint8_t LCR_gameStep(uint32_t time)
if (time >= LCR_nextRenderFrameTime)
{
int skyOffsetV = LCR_EFFECTIVE_RESOLUTION_Y / 2 +
((LCR_EFFECTIVE_RESOLUTION_Y / 2) *
LCR_rendererGetCameraPitch()) /
(LCR_SQUARE_SIDE_LEN / LCR_SETTING_SKY_ROLL_MULTIPLIER_V);
int skyOffsetH = LCR_SKY_IMAGE_SIZE - 1 -
(LCR_rendererGetCameraYaw() * LCR_SKY_IMAGE_SIZE) /
(LCR_SQUARE_SIDE_LEN / LCR_SETTING_SKY_ROLL_MULTIPLIER_H);
LCR_drawBackground(skyOffsetV);
LCR_drawBackground(0);
LCR_rendererDraw();
LCR_drawSkyStrip(skyOffsetV,skyOffsetH);
LCR_nextRenderFrameTime += 1000 / LCR_SETTING_FPS;

View file

@ -9,6 +9,9 @@
#define S3L_RESOLUTION_Y LCR_SETTING_RESOLUTION_Y
#define S3L_PIXEL_FUNCTION LCR_pixelFunc3D
#define S3L_PERSPECTIVE_CORRECTION 2
#define S3L_NEAR_CROSS_STRATEGY 0
#define S3L_Z_BUFFER 2
#include "small3dlib.h"
@ -28,9 +31,78 @@ S3L_Model3D *LCR_mapModel;
S3L_Unit LCR_mapVertices[LCR_SETTING_MAX_MAP_VERTICES * 3];
S3L_Index LCR_mapTriangles[LCR_SETTING_MAX_MAP_TRIANGLES * 3];
int _LCR_rendererPreviousTriangleID;
int _LCR_rendererTriangleUVs[6];
uint16_t _LCR_triangleShadingMask;
void LCR_pixelFunc3D(S3L_PixelInfo *pixel)
{
LCR_drawPixelXYSafe(pixel->x,pixel->y,0xff00 + (pixel->triangleID % 16) * 16 );
// once we get a new triangle, we precompute things for it:
if (pixel->triangleIndex != _LCR_rendererPreviousTriangleID)
{
S3L_Index *t = LCR_mapTriangles + 3 * pixel->triangleIndex;
S3L_Unit *v[3];
v[0] = LCR_mapVertices + 3 * t[0];
v[1] = LCR_mapVertices + 3 * t[1];
v[2] = LCR_mapVertices + 3 * t[2];
uint8_t type = // 0: floor, 1: wall, 2: wall 90 degrees
(v[0][0] == v[1][0] && v[1][0] == v[2][0]) +
2 * (v[0][2] == v[1][2] && v[1][2] == v[2][2]);
if (type == 0)
{
LCR_loadImage(1);
_LCR_triangleShadingMask = 0xffff;
for (int i = 0; i < 6; ++i)
_LCR_rendererTriangleUVs[i] = ((
(v[i / 2][(i % 2) * 2]) *
LCR_IMAGE_SIZE) / LCR_RENDERER_UNIT);
}
else
{
LCR_loadImage(0);
for (int i = 0; i < 6; ++i)
{
_LCR_rendererTriangleUVs[i] = ((
(v[i / 2][i % 2 ? 1 : (type == 1 ? 2 : 0)]) *
LCR_IMAGE_SIZE) / LCR_RENDERER_UNIT);
if (i % 2)
_LCR_rendererTriangleUVs[i] = LCR_IMAGE_SIZE -
_LCR_rendererTriangleUVs[i];
}
_LCR_triangleShadingMask = type == 1 ? 0xf7de : 0xe79c;
}
_LCR_rendererPreviousTriangleID = pixel->triangleIndex;
}
int barycentric[3];
barycentric[0] = pixel->barycentric[0] / 8;
barycentric[1] = pixel->barycentric[1] / 8;
barycentric[2] = pixel->barycentric[2] / 8;
uint16_t color = LCR_sampleImage(
(barycentric[0] * _LCR_rendererTriangleUVs[0] +
barycentric[1] * _LCR_rendererTriangleUVs[2] +
barycentric[2] * _LCR_rendererTriangleUVs[4])
/ (S3L_FRACTIONS_PER_UNIT / 8),
(barycentric[0] * _LCR_rendererTriangleUVs[1] +
barycentric[1] * _LCR_rendererTriangleUVs[3] +
barycentric[2] * _LCR_rendererTriangleUVs[5])
/ (S3L_FRACTIONS_PER_UNIT / 8)
) & _LCR_triangleShadingMask;
LCR_drawPixelXYUnsafe(pixel->x,pixel->y,color);
}
S3L_Index _LCR_addMapVertex(S3L_Unit x, S3L_Unit y, S3L_Unit z)
@ -91,6 +163,45 @@ void _LCR_rendererSwapTriangles(S3L_Index *t1, S3L_Index *t2)
}
}
int _LCR_quadCoversTriangle(const S3L_Unit quad[8], const S3L_Unit tri[6])
{
for (int i = 0; i < 3; ++i) // for each triangle point
{
int covered = 0;
for (int j = 0; j < 3; ++j) // for each quad subtriangle
{
uint8_t winds = 0;
for (int k = 0; k < 3; ++k) // for each subtriangle side
{
S3L_Unit w = // triangle winding
(quad[(2 * (j + ((k + 1) % 3))) % 8 + 1] -
quad[(2 * (j + k)) % 8 + 1]) *
(tri[2 * i] - quad[(2 * (j + (k + 1) % 3)) % 8]) -
(quad[(2 * (j + ((k + 1) % 3))) % 8] - quad[(2 * (j + k)) % 8])
* (tri[2 * i + 1] - quad[(2 * (j + (k + 1) % 3)) % 8 + 1]);
if (w > 0)
winds |= 1;
else if (w < 0)
winds |= 2;
}
if (winds != 3) // no opposite winds?
{
covered = 1;
break;
}
}
if (!covered)
return 0;
}
return 1;
}
/**
Checks whether two triangles (and potenrially their neighbors) cover each
other, in return values lowest bit means whether t1 is covered and the second
@ -194,45 +305,6 @@ uint8_t _LCR_rendererCheckMapTriangleCover(const S3L_Index *t1,
return result;
}
int _LCR_quadCoversTriangle(const S3L_Unit quad[8], const S3L_Unit tri[6])
{
for (int i = 0; i < 3; ++i) // for each triangle point
{
int covered = 0;
for (int j = 0; j < 3; ++j) // for each quad subtriangle
{
uint8_t winds = 0;
for (int k = 0; k < 3; ++k) // for each subtriangle side
{
S3L_Unit w = // triangle winding
(quad[(2 * (j + ((k + 1) % 3))) % 8 + 1] -
quad[(2 * (j + k)) % 8 + 1]) *
(tri[2 * i] - quad[(2 * (j + (k + 1) % 3)) % 8]) -
(quad[(2 * (j + ((k + 1) % 3))) % 8] - quad[(2 * (j + k)) % 8])
* (tri[2 * i + 1] - quad[(2 * (j + (k + 1) % 3)) % 8 + 1]);
if (w > 0)
winds |= 1;
else if (w < 0)
winds |= 2;
}
if (winds != 3) // no opposite winds?
{
covered = 1;
break;
}
}
if (!covered)
return 0;
}
return 1;
}
/**
Removes map triangles that are covered by other triangles (and also vertices
that by this become unused). This makes the map model smaller, faster and
@ -344,7 +416,6 @@ uint8_t _LCR_rendererBuildMapModel(void)
blockShapeBytes,&blockShapeByteCount);
uint8_t vx, vy, vz, vi = 0;
uint8_t *bytes = blockShapeBytes;
S3L_Index triangleIndices[3];
S3L_Unit originOffset = -1 * LCR_MAP_SIZE_BLOCKS / 2 * LCR_RENDERER_UNIT;
@ -421,6 +492,7 @@ void LCR_rendererMoveCamera(LCR_SpaceUnit forwRightUpOffset[3],
void LCR_rendererDraw(void)
{
_LCR_rendererPreviousTriangleID = -1;
S3L_newFrame();
S3L_drawScene(LCR_scene3D);
}
@ -428,81 +500,16 @@ void LCR_rendererDraw(void)
void LCR_drawBackground(int verticalOffset)
{
// TODO
for (int y = 0; y < LCR_EFFECTIVE_RESOLUTION_Y; ++y)
for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x)
LCR_drawPixelXYUnsafe(x,y,0xffff);
/*
uint16_t color = LCR_skyImages[LCR_skyImages[256] & 0x00ff] ; // TODO
int limit = verticalOffset - LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE / 2;
if (limit >= LCR_EFFECTIVE_RESOLUTION_Y)
limit = LCR_EFFECTIVE_RESOLUTION_Y - 1;
for (int y = 0; y <= limit; ++y)
for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x)
LCR_drawPixelUnsafe(x,y,color);
color = LCR_skyImages[LCR_skyImages[255 + (128 * 128) / 2] >> 8]; // TODO
limit = verticalOffset + LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE / 2 -
LCR_SETTING_SKY_SIZE;
if (limit < 0)
limit = 0;
for (int y = LCR_EFFECTIVE_RESOLUTION_Y - 1; y >= limit; --y)
for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x)
LCR_drawPixelUnsafe(x,y,color);
*/
}
void LCR_drawSkyStrip(int verticalOffset, uint8_t horizontalOffset)
{
#if LCR_SETTING_SKY_SIZE != 0
/*
verticalOffset -= (LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE) / 2;
int finalY = verticalOffset + LCR_SETTING_SKY_SIZE * LCR_SKY_IMAGE_SIZE;
finalY = (finalY / LCR_SETTING_SKY_SIZE) * LCR_SETTING_SKY_SIZE;
if (finalY >= LCR_EFFECTIVE_RESOLUTION_Y)
finalY = LCR_EFFECTIVE_RESOLUTION_Y - 1;
const uint16_t *skyLine = LCR_skyImages + 256;
if (verticalOffset < 0)
{
skyLine += (-1 * verticalOffset / LCR_SETTING_SKY_SIZE) * (LCR_SKY_IMAGE_SIZE / 2);
verticalOffset = 0;
}
while (verticalOffset < finalY)
{
for (int i = 0; i < LCR_EFFECTIVE_RESOLUTION_X; ++i)
{
// only diraw background on empty pixels
if (S3L_zBufferRead(i,verticalOffset) == S3L_MAX_DEPTH)
{
int offsetX = (i / LCR_SETTING_SKY_SIZE + horizontalOffset)
% LCR_SKY_IMAGE_SIZE;
uint16_t pixel = *(skyLine + offsetX / 2);
pixel = offsetX % 2 ? (pixel >> 8) : (pixel & 0x00ff);
LCR_drawPixelUnsafe(i,verticalOffset,LCR_skyImages[pixel]);
}
}
verticalOffset++;
if (verticalOffset % LCR_SETTING_SKY_SIZE == 0)
skyLine += LCR_SKY_IMAGE_SIZE / 2;
}
*/
#endif
}