Files
CgeMath/examples/demo.c

186 lines
5.5 KiB
C
Raw Normal View History

#include <math.h>
2026-07-04 18:10:01 +03:00
#include <stdio.h>
#include <string.h>
#include "CgeMath.h"
#define WIDTH 640
#define HEIGHT 480
#define MAX_BOUNCES 7
static int toInt(float x) {
return (int)(x * 255.0f);
}
typedef struct {
float center[3];
float radius;
const float *color;
float reflectivity;
float shininess;
float specular;
} Sphere;
2026-07-04 18:10:01 +03:00
static const float bg[3] = {0.05f, 0.05f, 0.1f};
2026-07-04 09:09:19 +03:00
static const float red[3] = {1.0f, 0.0f, 0.0f};
static const float green[3] = {0.0f, 1.0f, 0.0f};
static const float blue[3] = {0.0f, 0.0f, 1.0f};
static const Sphere spheres[] = {
{{-2.0f, 0.0f, -5.0f}, 1.0f, red, 0.1f, 20.0f, 0.5f},
{{ 0.0f, 2.0f, -4.0f}, 1.0f, green, 0.5f, 50.0f, 0.8f},
{{ 2.0f, 0.0f, -5.0f}, 1.0f, blue, 0.95f, 100.0f, 1.0f}
};
2026-07-04 09:09:19 +03:00
static const int numSpheres = 3;
static const float lightPos[3] = {0.0f, 3.0f, -2.0f};
static const float ambient = 0.2f;
static const float origin[3] = {0.0f, 0.5f, 0.0f};
int traceRay(const float origin[3], const float direction[3], float *t,
int *hitIndex, float hitPoint[3], float normal[3]) {
float t0, closest;
float p[3];
2026-07-04 18:10:01 +03:00
int i;
2026-07-04 18:10:01 +03:00
closest = 1.0 / 0.0;
*hitIndex = -1;
2026-07-04 09:09:19 +03:00
for (i = 0; i < numSpheres; i++) {
2026-07-04 18:10:01 +03:00
if (CgeRay3fIntersectSphere(origin, direction, spheres[i].center, spheres[i].radius, &t0, p)) {
if (t0 > 0.001f && t0 < closest) {
closest = t0;
2026-07-04 18:10:01 +03:00
*t = t0;
*hitIndex = i;
memcpy(hitPoint, p, sizeof(p));
CgeVec3fSub(hitPoint, spheres[i].center, normal);
CgeVec3fNormal(normal, normal);
}
}
}
2026-07-04 18:10:01 +03:00
t0 = (-1.0f - origin[1]) / direction[1];
if (t0 > 0.001f && t0 < closest) {
closest = t0;
*t = t0;
*hitIndex = -2;
2026-07-04 18:10:01 +03:00
CgeVec3fScale(direction, closest, hitPoint);
CgeVec3fAdd(origin, hitPoint, hitPoint);
normal[0] = 0.0f; normal[1] = 1.0f; normal[2] = 0.0f;
}
2026-07-04 18:10:01 +03:00
return *hitIndex != -1;
}
void traceColor(const float origin[3], const float direction[3], float color[3],
int depth) {
2026-07-04 18:10:01 +03:00
float normal[3], hitPoint[3];
float t;
int hitIndex;
if (depth >= MAX_BOUNCES) {
color[0] = color[1] = color[2] = 0.0f;
return;
}
2026-07-04 18:10:01 +03:00
if (traceRay(origin, direction, &t, &hitIndex, hitPoint, normal)) {
float localColor[3], toLight[3], lightDir[3];
float dummyPoint[3], dummyNormal[3];
float NdotL, diffuse, specular, brightness, reflectivity;
float shadow;
int dummyIdx;
2026-07-04 09:09:19 +03:00
CgeVec3fSub(lightPos, hitPoint, toLight);
CgeVec3fNormal(toLight, lightDir);
shadow = 1.0f;
2026-07-04 18:10:01 +03:00
if (traceRay(hitPoint, lightDir, &t, &dummyIdx, dummyPoint, dummyNormal)) {
2026-07-04 09:09:19 +03:00
float lightDist = CgeVec3fDistance(lightPos, hitPoint);
2026-07-04 18:10:01 +03:00
if (t < lightDist) {
shadow = 0.0f;
}
}
NdotL = CgeVec3fDot(normal, lightDir);
diffuse = (NdotL > 0.0f) ? NdotL : 0.0f;
specular = 0.0f;
if (hitIndex >= 0 && NdotL > 0.0f) {
2026-07-04 18:10:01 +03:00
float viewDir[3], halfVec[3];
float NdotH;
2026-07-04 09:09:19 +03:00
CgeVec3fSub(origin, hitPoint, viewDir);
CgeVec3fNormal(viewDir, viewDir);
CgeVec3fAdd(viewDir, lightDir, halfVec);
CgeVec3fNormal(halfVec, halfVec);
NdotH = CgeVec3fDot(normal, halfVec);
2026-07-04 18:10:01 +03:00
if (NdotH > 0.0f)
2026-07-04 09:09:19 +03:00
specular = powf(NdotH, spheres[hitIndex].shininess) * spheres[hitIndex].specular;
}
2026-07-04 09:09:19 +03:00
brightness = ambient + diffuse * shadow + specular * shadow;
if (hitIndex == -2) {
2026-07-04 18:10:01 +03:00
float tile;
int ix, iz;
ix = (int)floorf(hitPoint[0]);
iz = (int)floorf(hitPoint[2]);
tile = ((ix + iz) % 2 == 0) ? 1.0f : 0.3f;
localColor[0] = localColor[1] = localColor[2] = tile * brightness;
} else {
2026-07-04 18:10:01 +03:00
CgeVec3fScale(spheres[hitIndex].color, brightness, localColor);
}
2026-07-04 09:09:19 +03:00
reflectivity = (hitIndex >= 0) ? spheres[hitIndex].reflectivity : 0.0f;
if (reflectivity > 0.0f) {
2026-07-04 18:10:01 +03:00
float reflectDir[3], offset[3], reflectOrigin[3], reflectColor[3];
CgeVec3fReflect(direction, normal, reflectDir);
CgeVec3fScale(reflectDir, 0.001f, offset);
CgeVec3fAdd(hitPoint, offset, reflectOrigin);
traceColor(reflectOrigin, reflectDir, reflectColor, depth + 1);
2026-07-04 18:10:01 +03:00
CgeVec3fScale(localColor, (1.0f - reflectivity), localColor);
CgeVec3fScale(reflectColor, reflectivity, reflectColor);
CgeVec3fAdd(localColor, reflectColor, localColor);
}
2026-07-04 18:10:01 +03:00
memcpy(color, localColor, sizeof(localColor));
} else {
2026-07-04 18:10:01 +03:00
memcpy(color, bg, sizeof(bg));
}
}
int main() {
int x, y;
2026-07-04 18:10:01 +03:00
float aspect;
float direction[3], color[3];
printf("P3\n%d %d\n255\n", WIDTH, HEIGHT);
aspect = (float)WIDTH / (float)HEIGHT;
for (y = 0; y < HEIGHT; y++) {
for (x = 0; x < WIDTH; x++) {
2026-07-04 18:10:01 +03:00
direction[0] = (2.0f * (x + 0.5f) / (float)WIDTH - 1.0f) * aspect;
direction[1] = (2.0f * (HEIGHT - y - 0.5f) / (float)HEIGHT - 1.0f);
direction[2] = -1.0;
CgeVec3fNormal(direction, direction);
2026-07-04 09:09:19 +03:00
traceColor(origin, direction, color, 0);
2026-07-04 18:10:01 +03:00
CgeVec3fClamp(color, 0.0f, 1.0f, color);
color[0] = powf(color[0], 1.0f / 2.2f);
color[1] = powf(color[1], 1.0f / 2.2f);
color[2] = powf(color[2], 1.0f / 2.2f);
printf("%d %d %d\n", toInt(color[0]), toInt(color[1]), toInt(color[2]));
}
}
return 0;
}