Start atlas
This commit is contained in:
80
util/atlas.c
Normal file
80
util/atlas.c
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Created by bruno on 1.6.2025.
|
||||
//
|
||||
|
||||
#include "atlas.h"
|
||||
#include "util.h"
|
||||
|
||||
SDL_Texture *atlasTexture;
|
||||
|
||||
int atlasX = 0, atlasY = 0;
|
||||
|
||||
int tileIndex = 0; // Which 32x32 tile we're on
|
||||
int quadrantIndex = 0; // Which 16x16 slot inside that tile
|
||||
|
||||
|
||||
|
||||
SDL_Rect allocate_16x16(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
||||
SDL_Texture * oldTarget = SDL_GetRenderTarget(renderer);
|
||||
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||
int tileX = tileIndex % ATLAS_TILES_PER_ROW;
|
||||
int tileY = tileIndex / ATLAS_TILES_PER_ROW;
|
||||
|
||||
int dx = (quadrantIndex % 2) * QUADRANT_SIZE;
|
||||
int dy = (quadrantIndex / 2) * QUADRANT_SIZE;
|
||||
|
||||
SDL_Rect destRect = {
|
||||
tileX * TILE_SIZE + dx,
|
||||
tileY * TILE_SIZE + dy,
|
||||
QUADRANT_SIZE,
|
||||
QUADRANT_SIZE
|
||||
};
|
||||
SDL_RenderCopy(renderer, srcTexture, NULL, &destRect);
|
||||
|
||||
quadrantIndex++;
|
||||
if (quadrantIndex >= 4) {
|
||||
tileIndex++;
|
||||
quadrantIndex = 0;
|
||||
}
|
||||
SDL_SetRenderTarget(renderer, oldTarget);
|
||||
return destRect;
|
||||
}
|
||||
|
||||
SDL_Rect allocate_32x32(SDL_Texture *srcTexture, SDL_Renderer *renderer) {
|
||||
SDL_Texture * oldTarget = SDL_GetRenderTarget(renderer);
|
||||
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||
// If we’re not at the start of a tile, skip to the next clean one
|
||||
if (quadrantIndex != 0) {
|
||||
tileIndex++;
|
||||
quadrantIndex = 0;
|
||||
}
|
||||
|
||||
int tileX = tileIndex % ATLAS_TILES_PER_ROW;
|
||||
int tileY = tileIndex / ATLAS_TILES_PER_ROW;
|
||||
|
||||
SDL_Rect destRect = {
|
||||
tileX * TILE_SIZE,
|
||||
tileY * TILE_SIZE,
|
||||
TILE_SIZE,
|
||||
TILE_SIZE
|
||||
};
|
||||
SDL_RenderCopy(renderer, srcTexture, NULL, &destRect);
|
||||
|
||||
tileIndex++; // Move to next tile
|
||||
// quadrantIndex stays 0 — new tile is fresh
|
||||
SDL_SetRenderTarget(renderer, oldTarget);
|
||||
return destRect;
|
||||
}
|
||||
|
||||
void initAtlas(SDL_Renderer *renderer) {
|
||||
|
||||
// Clear atlas with transparent
|
||||
SDL_SetRenderTarget(renderer, atlasTexture);
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
|
||||
SDL_RenderClear(renderer);
|
||||
|
||||
|
||||
atlasTexture = SDL_CreateTexture(renderer,
|
||||
SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET,
|
||||
ATLAS_SIZE, ATLAS_SIZE);
|
||||
}
|
23
util/atlas.h
Normal file
23
util/atlas.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Created by bruno on 1.6.2025.
|
||||
//
|
||||
|
||||
#ifndef FACTORYGAME_ATLAS_H
|
||||
#define FACTORYGAME_ATLAS_H
|
||||
|
||||
#define ATLAS_SIZE 512
|
||||
#define TILE_SIZE 32
|
||||
#define QUADRANT_SIZE 16
|
||||
#define ATLAS_TILES_PER_ROW (ATLAS_SIZE / TILE_SIZE)
|
||||
|
||||
#include "SDL2/SDL.h"
|
||||
|
||||
extern SDL_Texture *atlasTexture;
|
||||
|
||||
SDL_Rect allocate_32x32(SDL_Texture *srcTexture, SDL_Renderer *renderer);
|
||||
|
||||
SDL_Rect allocate_16x16(SDL_Texture *srcTexture, SDL_Renderer *renderer);
|
||||
|
||||
void initAtlas(SDL_Renderer *renderer);
|
||||
|
||||
#endif //FACTORYGAME_ATLAS_H
|
113
util/audio.c
113
util/audio.c
@@ -6,21 +6,93 @@
|
||||
|
||||
AudioData audioData;
|
||||
|
||||
uint16_t getAvailableChannel() {
|
||||
for (uint16_t i = 0; i < NUM_SYNTH_VOICES; i++) {
|
||||
if (audioData.synthVoices[i].volume == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Helper: compute left/right gains from a pan value in [–1..+1]
|
||||
// pan = –1.0 → full left (L=1, R=0)
|
||||
// pan = +1.0 → full right (L=0, R=1)
|
||||
// pan = 0.0 → center (L=R=1/sqrt(2) or just 0.707 to avoid clipping)
|
||||
static void compute_stereo_gains(float pan, float *outL, float *outR) {
|
||||
// Simple linear panning (no constant‐power law).
|
||||
// If you prefer constant‐power, you could do:
|
||||
// float angle = (pan + 1.0f) * (M_PI / 4.0f);
|
||||
// *outL = cosf(angle);
|
||||
// *outR = sinf(angle);
|
||||
//
|
||||
// Here we’ll just do linear:
|
||||
pan = fmaxf(-1.0f, fminf(+1.0f, pan));
|
||||
if (pan <= 0.0f) {
|
||||
*outL = 1.0f;
|
||||
*outR = 1.0f + pan; // pan is negative, so R < 1
|
||||
} else {
|
||||
*outL = 1.0f - pan; // pan is positive, so L < 1
|
||||
*outR = 1.0f;
|
||||
}
|
||||
// Optionally, scale down both so we never exceed 1.0f / sqrt(2)
|
||||
// e.g. *outL *= 0.7071f; *outR *= 0.7071f;
|
||||
}
|
||||
|
||||
// This callback now writes stereo frames: interleaved L/R floats.
|
||||
void audio_callback(void *userdata, Uint8 *stream, int len) {
|
||||
AudioData *audio = (AudioData *) userdata;
|
||||
int samples = len / sizeof(float);
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
float mix = 0.0f;
|
||||
int activeVoices = 0;
|
||||
// 'len' is total bytes; each sample‐frame is 2 floats (L+R), i.e. 2 * sizeof(float).
|
||||
int frames = len / (2 * sizeof(float));
|
||||
|
||||
for (int v = 0; v < NUM_SYNTH_VOICES; v++) {
|
||||
SynthVoice *voice = &audio->synthVoices[v];
|
||||
if (voice->volume == 0 || voice->frequency == 0) continue;
|
||||
// Zero out the entire output buffer (silence)
|
||||
// We’ll accumulate into it.
|
||||
// Each float is 4 bytes, so total floats = 2 * frames.
|
||||
float *outBuf = (float *) stream;
|
||||
for (int i = 0; i < 2 * frames; ++i) {
|
||||
outBuf[i] = 0.0f;
|
||||
}
|
||||
|
||||
float sample;
|
||||
// Precompute the listener center
|
||||
float listenerCx = audio->playerRect->x + audio->playerRect->w * 0.5f;
|
||||
|
||||
// For each synth voice, mix into the stereo buffer
|
||||
for (int v = 0; v < NUM_SYNTH_VOICES; v++) {
|
||||
SynthVoice *voice = &audio->synthVoices[v];
|
||||
if (voice->volume == 0 || voice->frequency == 0) {
|
||||
continue; // skip silent or inactive voices
|
||||
}
|
||||
|
||||
// Compute source center X
|
||||
float sourceCx = voice->sourceRect.x + voice->sourceRect.w * 0.5f;
|
||||
float dx = sourceCx - listenerCx;
|
||||
|
||||
// Normalize for pan. If |dx| >= maxPanDistance → full left or full right.
|
||||
float pan = dx / audio->maxPanDistance;
|
||||
if (pan < -1.0f) pan = -1.0f;
|
||||
if (pan > +1.0f) pan = +1.0f;
|
||||
|
||||
float gainL, gainR;
|
||||
compute_stereo_gains(pan, &gainL, &gainR);
|
||||
|
||||
// Optional: You could also attenuate overall volume with distance
|
||||
// float dist = fabsf(dx);
|
||||
// float distanceAtten = 1.0f - fminf(dist / audio->maxPanDistance, 1.0f);
|
||||
// float finalVolume = (voice->volume / 255.0f) * distanceAtten;
|
||||
// But for now, we’ll just use voice->volume for amplitude.
|
||||
|
||||
float amp = (voice->volume / 255.0f);
|
||||
|
||||
// Phase increment per sample‐frame:
|
||||
// (freq * 256) / SAMPLE_RATE tells how many phase steps per mono-sample.
|
||||
// Because we’re writing stereo, we still advance phase once per frame.
|
||||
uint8_t phaseInc = (uint8_t)((voice->frequency * 256) / SAMPLE_RATE);
|
||||
|
||||
// Mix into each frame
|
||||
for (int i = 0; i < frames; i++) {
|
||||
float t = (float) voice->phase / 255.0f * 2.0f - 1.0f;
|
||||
|
||||
float sample;
|
||||
switch (voice->waveform) {
|
||||
default:
|
||||
case WAVE_SINE:
|
||||
@@ -33,18 +105,27 @@ void audio_callback(void *userdata, Uint8 *stream, int len) {
|
||||
sample = t;
|
||||
break;
|
||||
case WAVE_TRIANGLE:
|
||||
sample = (t < 0) ? -t : t;
|
||||
sample = (t < 0.0f) ? -t : t;
|
||||
break;
|
||||
case WAVE_NOISE:
|
||||
sample = ((float) rand() / RAND_MAX) * 2.0f - 1.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
voice->phase += (uint8_t) ((voice->frequency * 256) / SAMPLE_RATE);
|
||||
mix += sample * (voice->volume / 255.0f);
|
||||
activeVoices++;
|
||||
}
|
||||
voice->phase += phaseInc;
|
||||
|
||||
((float *) stream)[i] = (activeVoices > 0) ? mix / activeVoices : 0.0f;
|
||||
// Interleaved index: left = 2*i, right = 2*i + 1
|
||||
int idxL = 2 * i;
|
||||
int idxR = 2 * i + 1;
|
||||
|
||||
// Accumulate into buffer
|
||||
outBuf[idxL] += sample * amp * gainL;
|
||||
outBuf[idxR] += sample * amp * gainR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note: We did not normalize by active voices here, because each voice already
|
||||
// uses its own volume. If you still want an automatic “divide by N active voices”,
|
||||
// you would need to track active voices per‐frame, which is relatively expensive.
|
||||
// In practice, you manage the volume per voice so clipping doesn’t occur.
|
||||
}
|
19
util/audio.h
19
util/audio.h
@@ -11,9 +11,9 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#define SAMPLE_RATE 44100
|
||||
#define NUM_SYNTH_VOICES 3
|
||||
#define NUM_SYNTH_VOICES 256
|
||||
|
||||
typedef enum {
|
||||
typedef enum Waveform {
|
||||
WAVE_SINE,
|
||||
WAVE_SQUARE,
|
||||
WAVE_SAWTOOTH,
|
||||
@@ -21,19 +21,24 @@ typedef enum {
|
||||
WAVE_NOISE
|
||||
} Waveform;
|
||||
|
||||
typedef struct {
|
||||
uint8_t volume;
|
||||
uint16_t frequency;
|
||||
uint8_t phase;
|
||||
typedef struct SynthVoice {
|
||||
Waveform waveform;
|
||||
uint8_t phase;
|
||||
uint16_t frequency;
|
||||
uint8_t volume;
|
||||
SDL_Rect sourceRect;
|
||||
} SynthVoice;
|
||||
|
||||
typedef struct {
|
||||
typedef struct AudioData {
|
||||
SynthVoice synthVoices[NUM_SYNTH_VOICES];
|
||||
SDL_Rect *playerRect;
|
||||
float maxPanDistance;
|
||||
} AudioData;
|
||||
|
||||
extern AudioData audioData;
|
||||
|
||||
void audio_callback(void *userdata, Uint8 *stream, int len);
|
||||
|
||||
uint16_t getAvailableChannel();
|
||||
|
||||
#endif //RISCB_AUDIO_H
|
||||
|
@@ -11,7 +11,7 @@
|
||||
|
||||
#define fontCount 4
|
||||
|
||||
typedef struct {
|
||||
typedef struct BitmapFont {
|
||||
SDL_Texture *texture[256];
|
||||
SDL_Surface *surface[256];
|
||||
uint8_t size;
|
||||
|
52
util/perlin.c
Normal file
52
util/perlin.c
Normal file
@@ -0,0 +1,52 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
double rawnoise(int n) {
|
||||
n = (n << 13) ^ n;
|
||||
return (1.0 - ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0);
|
||||
}
|
||||
|
||||
double noise2d(int x, int y, int octave, int seed) {
|
||||
return rawnoise(x * 1619 + y * 31337 + octave * 3463 + seed * 13397);
|
||||
}
|
||||
|
||||
double interpolate(double a, double b, double x) {
|
||||
double f = (1 - cos(x * 3.141593)) * 0.5;
|
||||
|
||||
return a * (1 - f) + b * f;
|
||||
}
|
||||
|
||||
double smooth2d(double x, double y, int octave, int seed) {
|
||||
int intx = (int) x;
|
||||
double fracx = x - intx;
|
||||
int inty = (int) y;
|
||||
double fracy = y - inty;
|
||||
|
||||
double v1 = noise2d(intx, inty, octave, seed);
|
||||
double v2 = noise2d(intx + 1, inty, octave, seed);
|
||||
double v3 = noise2d(intx, inty + 1, octave, seed);
|
||||
double v4 = noise2d(intx + 1, inty + 1, octave, seed);
|
||||
|
||||
double i1 = interpolate(v1, v2, fracx);
|
||||
double i2 = interpolate(v3, v4, fracx);
|
||||
|
||||
return interpolate(i1, i2, fracy);
|
||||
}
|
||||
|
||||
|
||||
double pnoise2d(double x, double y, double persistence, int octaves, int seed) {
|
||||
double total = 0.0;
|
||||
double frequency = 1.0;
|
||||
double amplitude = 1.0;
|
||||
double max = 0.0;
|
||||
|
||||
for (int i = 0; i < octaves; i++) {
|
||||
total += smooth2d(x * frequency, y * frequency, i, seed) * amplitude;
|
||||
max += amplitude;
|
||||
frequency /= 2.0;
|
||||
amplitude *= persistence;
|
||||
}
|
||||
|
||||
// Normalize to [0, 1]
|
||||
return (total + max) / (2.0 * max);
|
||||
}
|
10
util/perlin.h
Normal file
10
util/perlin.h
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by bruno on 1.6.2025.
|
||||
//
|
||||
|
||||
#ifndef FACTORYGAME_PERLIN_H
|
||||
#define FACTORYGAME_PERLIN_H
|
||||
|
||||
double pnoise2d(double x, double y, double persistence, int octaves, int seed);
|
||||
|
||||
#endif //FACTORYGAME_PERLIN_H
|
@@ -6,11 +6,13 @@
|
||||
#include "util.h"
|
||||
//#include "font.h"
|
||||
|
||||
|
||||
//The window we'll be rendering to
|
||||
SDL_Window *window = NULL;
|
||||
volatile bool running = true;
|
||||
|
||||
bool debugMode = false;
|
||||
bool itemViewing = false;
|
||||
|
||||
//The surface contained by the window
|
||||
SDL_Renderer *mainRenderer = NULL;
|
||||
|
@@ -16,7 +16,7 @@ extern SDL_Renderer *mainRenderer;
|
||||
|
||||
extern SDL_Rect screenRect;
|
||||
|
||||
typedef enum {
|
||||
typedef enum OrientDirection{
|
||||
ORIENT_LEFT_DOWN,
|
||||
ORIENT_LEFT,
|
||||
ORIENT_LEFT_UP,
|
||||
@@ -29,6 +29,7 @@ typedef enum {
|
||||
} OrientDirection;
|
||||
|
||||
extern bool debugMode;
|
||||
extern bool itemViewing;
|
||||
|
||||
SDL_Texture *createRotatedTexture(SDL_Renderer *renderer, SDL_Texture *src, double angle);
|
||||
|
||||
|
Reference in New Issue
Block a user