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) 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); 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_mapLoad(map1);
LCR_rendererInit(); LCR_rendererInit();
LCR_loadImage(0);
} }
void LCR_gameEnd(void) void LCR_gameEnd(void)
@ -127,18 +130,8 @@ uint8_t LCR_gameStep(uint32_t time)
if (time >= LCR_nextRenderFrameTime) if (time >= LCR_nextRenderFrameTime)
{ {
int skyOffsetV = LCR_EFFECTIVE_RESOLUTION_Y / 2 + LCR_drawBackground(0);
((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_rendererDraw(); LCR_rendererDraw();
LCR_drawSkyStrip(skyOffsetV,skyOffsetH);
LCR_nextRenderFrameTime += 1000 / LCR_SETTING_FPS; LCR_nextRenderFrameTime += 1000 / LCR_SETTING_FPS;

View file

@ -9,6 +9,9 @@
#define S3L_RESOLUTION_Y LCR_SETTING_RESOLUTION_Y #define S3L_RESOLUTION_Y LCR_SETTING_RESOLUTION_Y
#define S3L_PIXEL_FUNCTION LCR_pixelFunc3D #define S3L_PIXEL_FUNCTION LCR_pixelFunc3D
#define S3L_PERSPECTIVE_CORRECTION 2
#define S3L_NEAR_CROSS_STRATEGY 0
#define S3L_Z_BUFFER 2 #define S3L_Z_BUFFER 2
#include "small3dlib.h" #include "small3dlib.h"
@ -28,9 +31,78 @@ S3L_Model3D *LCR_mapModel;
S3L_Unit LCR_mapVertices[LCR_SETTING_MAX_MAP_VERTICES * 3]; S3L_Unit LCR_mapVertices[LCR_SETTING_MAX_MAP_VERTICES * 3];
S3L_Index LCR_mapTriangles[LCR_SETTING_MAX_MAP_TRIANGLES * 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) 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) 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 Checks whether two triangles (and potenrially their neighbors) cover each
other, in return values lowest bit means whether t1 is covered and the second 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; 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 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 that by this become unused). This makes the map model smaller, faster and
@ -344,7 +416,6 @@ uint8_t _LCR_rendererBuildMapModel(void)
blockShapeBytes,&blockShapeByteCount); blockShapeBytes,&blockShapeByteCount);
uint8_t vx, vy, vz, vi = 0; uint8_t vx, vy, vz, vi = 0;
uint8_t *bytes = blockShapeBytes;
S3L_Index triangleIndices[3]; S3L_Index triangleIndices[3];
S3L_Unit originOffset = -1 * LCR_MAP_SIZE_BLOCKS / 2 * LCR_RENDERER_UNIT; 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) void LCR_rendererDraw(void)
{ {
_LCR_rendererPreviousTriangleID = -1;
S3L_newFrame(); S3L_newFrame();
S3L_drawScene(LCR_scene3D); S3L_drawScene(LCR_scene3D);
} }
@ -428,81 +500,16 @@ void LCR_rendererDraw(void)
void LCR_drawBackground(int verticalOffset) void LCR_drawBackground(int verticalOffset)
{ {
// TODO
for (int y = 0; y < LCR_EFFECTIVE_RESOLUTION_Y; ++y) for (int y = 0; y < LCR_EFFECTIVE_RESOLUTION_Y; ++y)
for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x) for (int x = 0; x < LCR_EFFECTIVE_RESOLUTION_X; ++x)
LCR_drawPixelXYUnsafe(x,y,0xffff); 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) void LCR_drawSkyStrip(int verticalOffset, uint8_t horizontalOffset)
{ {
#if LCR_SETTING_SKY_SIZE != 0 #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 #endif
} }