[Add] Initial commit of Lephisto.
This commit is contained in:
parent
227242c447
commit
cc47d41137
28
.gitignore
vendored
Normal file
28
.gitignore
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
# Object files
|
||||
*.o
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
*.bin
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Crap.
|
||||
*.log
|
||||
*.swp
|
||||
*.txt
|
||||
*.tsv
|
||||
*.pdf
|
||||
*bin/Lephisto
|
||||
|
||||
|
26
bin/Makefile
Normal file
26
bin/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
DEBUG = 1
|
||||
APPNAME = Lephisto
|
||||
|
||||
OBJ := ../src/main.o \
|
||||
../src/physics.o \
|
||||
../src/opengl.o \
|
||||
../src/ship.o \
|
||||
../src/pilot.o
|
||||
|
||||
CFLAGS = -Wall `sdl-config --cflags`
|
||||
ifdef DEBUG
|
||||
CFLAGS += -g3 -DDEBUG
|
||||
else
|
||||
CFLAGS += -O2
|
||||
endif
|
||||
|
||||
LDFLAGS = -lm `sdl-config --libs` -lSDL_image -lGL
|
||||
|
||||
%.o: ../src/%.c
|
||||
gcc -c $(CFLAGS) -o $@ $<
|
||||
|
||||
all: $(OBJ)
|
||||
gcc $(LDFLAGS) -o $(APPNAME) $(OBJ)
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJ) $(APPNAME)
|
BIN
gfx/ship.png
Normal file
BIN
gfx/ship.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 91 KiB |
6
src/def.h
Normal file
6
src/def.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define MALLOC_L(type)(malloc(sizeof(type)))
|
||||
|
||||
typedef float FP;
|
||||
|
14
src/log.h
Normal file
14
src/log.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
|
||||
#define LOG(str, args...)(fprintf(stdout, str"\n", ## args))
|
||||
#define WARN(str, args...)(fprintf(stderr, "[%d] "str"\n", 0, ## args))
|
||||
|
||||
#ifdef DEBUG
|
||||
# undef DEBUG
|
||||
# define DEBUG(str, args...) LOG(str, ## args)
|
||||
# define DEBUGGING
|
||||
#else
|
||||
# define DEBUG(str, args...) do {;} while(0)
|
||||
#endif
|
||||
|
93
src/main.c
93
src/main.c
@ -1,2 +1,95 @@
|
||||
#include <SDL.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "def.h"
|
||||
#include "log.h"
|
||||
#include "log.h"
|
||||
#include "physics.h"
|
||||
#include "opengl.h"
|
||||
#include "ship.h"
|
||||
#include "pilot.h"
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
int quit = 0;
|
||||
SDL_Event event;
|
||||
|
||||
gl_screen.w = 800;
|
||||
gl_screen.h = 640;
|
||||
gl_screen.fullscreen = 0;
|
||||
|
||||
gl_init();
|
||||
|
||||
gl_texture* tex;
|
||||
if((tex = gl_newSprite("../gfx/ship.png", 6, 6)) == NULL) {
|
||||
WARN("Unable to load image");
|
||||
return -1;
|
||||
}
|
||||
Ship* ship = MALLOC_L(Ship);
|
||||
ship->gfx_ship = tex;
|
||||
ship->mass = 1;
|
||||
ship->class = SHIP_CLASS_CIVILIAN;
|
||||
Pilot* player = pilot_create(ship, "player", NULL, NULL, PILOT_PLAYER);
|
||||
gl_bindCamera(&player->solid->pos);
|
||||
|
||||
int tflag = 0;
|
||||
unsigned int time = SDL_GetTicks();
|
||||
FP dt;
|
||||
while(!quit) {
|
||||
while(SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
switch(event.key.keysym.sym) {
|
||||
case SDLK_q:
|
||||
quit = 1;
|
||||
break;
|
||||
case SDLK_a:
|
||||
tflag ^= 1;
|
||||
break;
|
||||
case SDLK_d:
|
||||
tflag ^=2;
|
||||
case SDLK_w:
|
||||
tflag ^= 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SDL_KEYUP:
|
||||
switch(event.key.keysym.sym) {
|
||||
case SDLK_a:
|
||||
tflag ^= 1;
|
||||
break;
|
||||
case SDLK_d:
|
||||
tflag ^= 2;
|
||||
break;
|
||||
case SDLK_w:
|
||||
tflag ^= 8;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
dt = (FP)(SDL_GetTicks() - time) / 1000.0;
|
||||
if(tflag & 1) player->solid->dir += 200.0 / 180.0*M_PI*dt;
|
||||
if(tflag & 2) player->solid->dir -= 200.0 / 180.0*M_PI*dt;
|
||||
if(tflag & 8) player->solid->force = 340;
|
||||
else player->solid->force = 0;
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
player->update(player, dt);
|
||||
SDL_GL_SwapBuffers();
|
||||
time = SDL_GetTicks();
|
||||
SDL_Delay(5);
|
||||
}
|
||||
|
||||
pilot_free(player);
|
||||
free(ship);
|
||||
gl_free(tex);
|
||||
|
||||
gl_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
302
src/opengl.c
Normal file
302
src/opengl.c
Normal file
@ -0,0 +1,302 @@
|
||||
#include <SDL.h>
|
||||
#include <SDL_image.h>
|
||||
#include "def.h"
|
||||
#include "log.h"
|
||||
#include "opengl.h"
|
||||
|
||||
// Recommended for compatibility bullshit.
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
# define RMASK 0xff000000
|
||||
# define GMASK 0x00ff0000
|
||||
# define BMASK 0x0000ff00
|
||||
# define AMASK 0x000000ff
|
||||
#else
|
||||
# define RMASK 0x000000ff
|
||||
# define GMASK 0x0000ff00
|
||||
# define BMASK 0x00ff0000
|
||||
# define AMASK 0xff000000
|
||||
#endif
|
||||
#define RGBMASK RMASK,GMASK,BMASK,AMASK
|
||||
|
||||
// The screen info, gives data of current opengl settings.
|
||||
gl_info gl_screen;
|
||||
|
||||
// Our precious camera.
|
||||
Vec2* gl_camera;
|
||||
|
||||
static int flip_surface(SDL_Surface* surface);
|
||||
|
||||
// Flips the surface vertically. Return 0 on success.
|
||||
static int flip_surface(SDL_Surface* surface) {
|
||||
// Flip the image.
|
||||
Uint8* rowhi, *rowlo, *tmpbuf;
|
||||
int y;
|
||||
|
||||
tmpbuf = (Uint8*)malloc(surface->pitch);
|
||||
if(tmpbuf == NULL) {
|
||||
WARN("Out of memory");
|
||||
return -1;
|
||||
}
|
||||
|
||||
rowhi = (Uint8*)surface->pixels;
|
||||
rowlo = rowhi + (surface->h * surface->pitch) - surface->pitch;
|
||||
for(y = 0; y < surface->h / 2; ++y) {
|
||||
memcpy(tmpbuf, rowhi, surface->pitch);
|
||||
memcpy(rowhi, rowlo, surface->pitch);
|
||||
memcpy(rowlo, tmpbuf, surface->pitch);
|
||||
rowhi += surface->pitch;
|
||||
rowlo -= surface->pitch;
|
||||
}
|
||||
free(tmpbuf);
|
||||
// Might be obvious, but I'm done flipping.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Load the image directly as an opengl texture.
|
||||
gl_texture* gl_newImage(const char* path) {
|
||||
SDL_Surface* tmp, *surface;
|
||||
Uint32 saved_flags;
|
||||
Uint8 saved_alpha;
|
||||
int potw, poth;
|
||||
|
||||
tmp = IMG_Load(path); // Load the surface.
|
||||
if(tmp == 0) {
|
||||
WARN("'%s' could not be opened: %s", path, IMG_GetError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
surface = SDL_DisplayFormatAlpha(tmp); // Set the surface to what we use.
|
||||
if(surface == 0) {
|
||||
WARN("Error converting image to screen format: %s", SDL_GetError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_FreeSurface(tmp); // Free the temp surface.
|
||||
|
||||
flip_surface(surface);
|
||||
|
||||
// Set up the texture defaults.
|
||||
gl_texture* texture = MALLOC_L(gl_texture);
|
||||
texture->w = (FP)surface->w;
|
||||
texture->h = (FP)surface->h;
|
||||
texture->sx = 1.0;
|
||||
texture->sy = 1.0;
|
||||
|
||||
// Ensure size is power of two.
|
||||
potw = surface->w;
|
||||
if((potw &(potw-1)) != 0) {
|
||||
potw = 1;
|
||||
while(potw < surface->w)
|
||||
potw <<= 1;
|
||||
}
|
||||
texture->rw = potw;
|
||||
|
||||
poth = surface->h;
|
||||
if((poth &(poth-1)) != 0) {
|
||||
poth = 1;
|
||||
while(poth < surface->h)
|
||||
poth <<= 1;
|
||||
}
|
||||
texture->rh = poth;
|
||||
|
||||
if(surface->w != potw || surface->h != poth) {
|
||||
// Size isn't original.
|
||||
SDL_Rect rtemp;
|
||||
rtemp.x = rtemp.y = 0;
|
||||
rtemp.w = surface->w;
|
||||
rtemp.h = surface->h;
|
||||
|
||||
// Save alpha.
|
||||
saved_flags = surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
|
||||
saved_alpha = surface->format->alpha;
|
||||
if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
|
||||
SDL_SetAlpha(surface, 0, 0);
|
||||
|
||||
// Create the temp POT surface.
|
||||
tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY,
|
||||
texture->rw, texture->rh, surface->format->BytesPerPixel*8, RGBMASK);
|
||||
if(tmp == NULL) {
|
||||
WARN("Unable to create POT surface %s", SDL_GetError());
|
||||
return 0;
|
||||
}
|
||||
if(SDL_FillRect(tmp, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, SDL_ALPHA_TRANSPARENT))) {
|
||||
WARN("Unable to fill rect: %s", SDL_GetError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_BlitSurface(surface, &rtemp, tmp, &rtemp);
|
||||
SDL_FreeSurface(surface);
|
||||
|
||||
surface = tmp;
|
||||
|
||||
// Set saved alpha.
|
||||
if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA)
|
||||
SDL_SetAlpha(surface, saved_flags, saved_alpha);
|
||||
}
|
||||
|
||||
glGenTextures(1, &texture->texture); // Create the texure.
|
||||
glBindTexture(GL_TEXTURE_2D, texture->texture); // Load the texture.
|
||||
|
||||
// Filtering, LINEAR is better for scaling, nearest looks nicer, LINEAR
|
||||
// also seems to create a bit of artifacts around the edges.
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
SDL_LockSurface(surface);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel,
|
||||
surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
|
||||
|
||||
SDL_UnlockSurface(surface);
|
||||
SDL_FreeSurface(surface);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Load the texture immediately, but also set is as a sprite.
|
||||
gl_texture* gl_newSprite(const char* path, const int sx, const int sy) {
|
||||
gl_texture* texture;
|
||||
if((texture = gl_newImage(path)) == NULL)
|
||||
return NULL;
|
||||
texture->sx = (FP)sx;
|
||||
texture->sy = (FP)sy;
|
||||
texture->sw = texture->w/texture->sx;
|
||||
texture->sh = texture->h/texture->sy;
|
||||
return texture;
|
||||
}
|
||||
|
||||
// Free the texture.
|
||||
void gl_free(gl_texture* texture) {
|
||||
glDeleteTextures(1, &texture->texture);
|
||||
free(texture);
|
||||
}
|
||||
|
||||
// Blit the sprite at given position.
|
||||
void gl_blitSprite(gl_texture* sprite, Vec2* pos, const int sx, const int sy) {
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glTranslatef(sprite->sw * (FP)(sx)/sprite->rw,
|
||||
sprite->sh*(sprite->sy-(FP)sy-1)/sprite->rh, 0.0f);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix(); // Projection translation matrix.
|
||||
glTranslatef(gl_camera->x - pos->x - sprite->sw / 2.0,
|
||||
gl_camera->y - pos->y - sprite->sh/2.0, 0.0f);
|
||||
|
||||
// Actual blitting....
|
||||
glBindTexture(GL_TEXTURE_2D, sprite->texture);
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
glTexCoord2f(sprite->sw/sprite->rw, 0.0f);
|
||||
glVertex2f(sprite->sw, 0.0f);
|
||||
glTexCoord2f(0.0f, sprite->sh/sprite->rh);
|
||||
glVertex2f(0.0f, sprite->sh);
|
||||
glTexCoord2f(sprite->sw/sprite->rw, sprite->sh/sprite->rh);
|
||||
glVertex2f(sprite->sw, sprite->sh);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix(); // Projection translation matrix.
|
||||
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glPopMatrix(); // Sprite translation matrix.
|
||||
}
|
||||
|
||||
// Just straight out blit the thing at position.
|
||||
void gl_blit(gl_texture* texture, Vec2* pos) {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix(); // Set up translation matrix.
|
||||
glTranslatef(pos->x, pos->y, 0);
|
||||
|
||||
// Actual blitting..
|
||||
glBindTexture(GL_TEXTURE_2D, texture->texture);
|
||||
glBegin(GL_TRIANGLE_STRIP);
|
||||
glTexCoord2f(0.0f, 0.0f);
|
||||
glVertex2f(0.0f, 0.0f);
|
||||
glTexCoord2f(texture->w/texture->rw, 0.0f);
|
||||
glVertex2f(texture->w, 0.0f);
|
||||
glTexCoord2f(0.0f, texture->h/texture->rh);
|
||||
glVertex2f(0.0f, texture->h);
|
||||
glTexCoord2f(texture->w/texture->rw, texture->h/texture->rh);
|
||||
glVertex2f(texture->w, texture->h);
|
||||
glEnd();
|
||||
|
||||
glPopMatrix(); // Pop the translation matrix.
|
||||
}
|
||||
|
||||
// Bind our precious camera to a vector.
|
||||
void gl_bindCamera(Vec2* pos) {
|
||||
gl_camera = pos;
|
||||
}
|
||||
|
||||
// Initialize SDL/OpenGL etc.
|
||||
int gl_init(void) {
|
||||
int depth;
|
||||
int flags = SDL_OPENGL;
|
||||
|
||||
// Initializes video.
|
||||
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
WARN("Unable to initialize SDL: %s", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
// FFUUUU Ugly cursor thing.
|
||||
SDL_ShowCursor(SDL_DISABLE);
|
||||
|
||||
flags |= SDL_FULLSCREEN* gl_screen.fullscreen;
|
||||
depth = SDL_VideoModeOK(gl_screen.w, gl_screen.h, gl_screen.depth, flags); // Test set up.
|
||||
if(depth != gl_screen.depth)
|
||||
WARN("Depth: %d bpp unavailable, will use %d bpp", gl_screen.depth, depth);
|
||||
|
||||
gl_screen.depth = depth;
|
||||
|
||||
// Actually creating the screen.
|
||||
if(SDL_SetVideoMode(gl_screen.w, gl_screen.h, gl_screen.depth, flags) == NULL) {
|
||||
WARN("Unable to create OpenGL window: %s", SDL_GetError());
|
||||
SDL_Quit();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Grab some info.
|
||||
SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &gl_screen.r);
|
||||
SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gl_screen.g);
|
||||
SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &gl_screen.b);
|
||||
SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &gl_screen.a);
|
||||
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &gl_screen.doublebuf);
|
||||
gl_screen.depth = gl_screen.r + gl_screen.g + gl_screen.b + gl_screen.a;
|
||||
|
||||
// Debug heaven.
|
||||
DEBUG("OpenGL Window Created: %dx%d@%dbpp %s", gl_screen.w, gl_screen.h, gl_screen.depth,
|
||||
gl_screen.fullscreen ? "fullscreen" : "window");
|
||||
DEBUG("r: %d, g: %d, b: %d, a: %d, doublebuffer: %s", gl_screen.r, gl_screen.g, gl_screen.b, gl_screen.a,
|
||||
gl_screen.doublebuf ? "yes" : "no");
|
||||
DEBUG("Renderer: %s", glGetString(GL_RENDERER));
|
||||
|
||||
// Some openGL options.
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glDisable(GL_DEPTH_TEST); // Set for doing 2D shidazles.
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(-gl_screen.w/2, // Left edge.
|
||||
gl_screen.w/2, // Right edge.
|
||||
-gl_screen.h/2, // Bottom edge.
|
||||
gl_screen.h/2, // Top edge.
|
||||
-1.0f, // Near.
|
||||
1.0f); // Far.
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Alpha.
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
SDL_WM_SetCaption(WINDOW_CAPTION, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Clean up our mess.
|
||||
void gl_exit(void) {
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
SDL_Quit();
|
||||
}
|
||||
|
40
src/opengl.h
Normal file
40
src/opengl.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include "SDL_opengl.h"
|
||||
#include "physics.h"
|
||||
|
||||
#define WINDOW_CAPTION "Lephisto"
|
||||
|
||||
// Info about opengl screen.
|
||||
typedef struct {
|
||||
int w, h; // Window dimensions.
|
||||
int depth; // Depth in bpp.
|
||||
int fullscreen; // 1 = fullscreen, 0 = windowed.
|
||||
int r, g, b, a; // Framebuffer values in bits.
|
||||
int doublebuf; // Double buffer.
|
||||
} gl_info;
|
||||
|
||||
extern gl_info gl_screen; // Local structure set with gl_init etc.
|
||||
|
||||
// Spritesheet info.
|
||||
typedef struct {
|
||||
FP w, h; // Real size of the image (excluding POT buffer.
|
||||
FP rw, rh; // Size of POT surface.
|
||||
FP sx, sy; // Number of sprites on x and y axes.
|
||||
FP sw, sh; // Size of each sprite.
|
||||
GLuint texture; // The opengl texture itself.
|
||||
} gl_texture;
|
||||
|
||||
// gl_texute loading/freeing.
|
||||
gl_texture* gl_newImage(const char* path);
|
||||
gl_texture* gl_newSprite(const char* path, const int sx, const int sy);
|
||||
void gl_free(gl_texture* texture);
|
||||
|
||||
// Rendering.
|
||||
void gl_blitSprite(gl_texture* sprite, Vec2* pos, const int sx, const int sy);
|
||||
void gl_blit(gl_texture* texture, Vec2* pos);
|
||||
void gl_bindCamera(Vec2* pos);
|
||||
|
||||
// Initialize/cleanup.
|
||||
int gl_init(void);
|
||||
void gl_exit(void);
|
||||
|
134
src/physics.c
Normal file
134
src/physics.c
Normal file
@ -0,0 +1,134 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "physics.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846f
|
||||
#endif
|
||||
|
||||
// Pretty efficient, no need for sine table!!
|
||||
#define SIN(dir)(sinf(dir))
|
||||
#define COS(dir)(cosf(dir))
|
||||
|
||||
// ==Update method.========================================
|
||||
// d^2 x(t) / d t^2 = a, a = constant (acceleration)
|
||||
// x'(0) = v, x(0) = p
|
||||
//
|
||||
// d x(t) / d t = a*t + v, v = constant (initial velocity)
|
||||
// x(t) = a/2*t + v*t + p, p = constant (initial position)
|
||||
//
|
||||
// Since dt isn't actually differential this gives us an
|
||||
// error, so watch out with big values for dt.
|
||||
// ========================================================
|
||||
|
||||
static void simple_update(Solid* obj, const FP dt) {
|
||||
if(obj->force) {
|
||||
Vec2 acc;
|
||||
acc.x = obj->force / obj->mass * COS(obj->dir);
|
||||
acc.y = obj->force / obj->mass * SIN(obj->dir);
|
||||
|
||||
obj->pos.x += acc.x * dt;
|
||||
obj->vel.y += acc.y * dt;
|
||||
|
||||
obj->pos.x += obj->vel.x * dt + 0.5 * acc.x / obj->mass * dt * dt;
|
||||
obj->pos.y += obj->vel.y * dt + 0.5 * acc.y / obj->mass * dt * dt;
|
||||
} else {
|
||||
obj->pos.x += obj->vel.x * dt;
|
||||
obj->pos.y += obj->vel.y * dt;
|
||||
}
|
||||
}
|
||||
|
||||
// ==Runge-Kutta 4th method.===============================
|
||||
// d^2 x(t) / d t^2 = a, a = constant(acceleration)
|
||||
// x'(0) = v, x(0) = p
|
||||
// x'' = f(t, x, x') = (x', a)
|
||||
//
|
||||
// x_ {n+1} = x_n + h/6 (k1 + 2*k2 + 3*k3 + k4)
|
||||
// h = (b-a)/2
|
||||
// k1 = f(t_n, X_n), X_n = (x_n, x'_n)
|
||||
// k2 = f(t_n + h/2, X_n + h/2*k1)
|
||||
// k3 = f(t_n + h/2, X_n + h/2*k2)
|
||||
// k4 = f(t_n + h, X_n + h*k3)
|
||||
//
|
||||
// x_{n+1} = x_n + h/6x'_n + 3*h*a, 4*a)
|
||||
// ========================================================
|
||||
|
||||
#define RK4_N 4
|
||||
static void rk4_update(Solid* obj, const FP dt) {
|
||||
FP h = dt / RK4_N; // Step.
|
||||
|
||||
if(obj->force) { // Force applied on object.
|
||||
int i;
|
||||
Vec2 initial, tmp;
|
||||
|
||||
Vec2 acc;
|
||||
acc.x = obj->force / obj->mass * COS(obj->dir);
|
||||
acc.y = obj->force / obj->mass * SIN(obj->dir);
|
||||
|
||||
for(i = 0; i < RK4_N; i++) {
|
||||
// X component.
|
||||
tmp.x = initial.x = obj->vel.x;
|
||||
tmp.x += 2*initial.x + h*tmp.x;
|
||||
tmp.x += 2*initial.x + h*tmp.x;
|
||||
tmp.x += initial.x + h*tmp.x;
|
||||
tmp.x *= h/6;
|
||||
|
||||
obj->pos.x += tmp.x;
|
||||
obj->vel.x += acc.x*h;
|
||||
|
||||
// Y component.
|
||||
tmp.y = initial.y = obj->vel.y;
|
||||
tmp.y += 2*(initial.y + h/2*tmp.y);
|
||||
tmp.y += 2*(initial.y + h/2*tmp.y);
|
||||
tmp.y += initial.y + h*tmp.y;
|
||||
tmp.y *= h/6;
|
||||
|
||||
obj->pos.y += tmp.y;
|
||||
obj->pos.y += acc.y*h;
|
||||
}
|
||||
} else {
|
||||
obj->pos.x += dt*obj->vel.x;
|
||||
obj->pos.y += dt*obj->vel.y;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize a new solid.
|
||||
void solid_init(Solid* dest, const FP mass, const Vec2* vel, const Vec2* pos) {
|
||||
dest->mass = mass;
|
||||
|
||||
dest->force = 0;
|
||||
dest->dir = 0;
|
||||
|
||||
if(vel == NULL)
|
||||
dest->vel.x = dest->vel.y = 0.0;
|
||||
else {
|
||||
dest->vel.x = vel->x;
|
||||
dest->vel.y = vel->y;
|
||||
}
|
||||
|
||||
if(pos == NULL)
|
||||
dest->pos.x = dest->pos.y = 0.0;
|
||||
else {
|
||||
dest->pos.x = pos->x;
|
||||
dest->pos.y = pos->y;
|
||||
}
|
||||
|
||||
dest->update = rk4_update;
|
||||
}
|
||||
|
||||
// Create a new solid.
|
||||
Solid* solid_create(const FP mass, const Vec2* vel, const Vec2* pos) {
|
||||
Solid* dyn = MALLOC_L(Solid);
|
||||
assert(dyn != NULL);
|
||||
solid_init(dyn, mass, vel, pos);
|
||||
return dyn;
|
||||
}
|
||||
|
||||
// Free an existing solid.
|
||||
void solid_free(Solid* src) {
|
||||
free(src);
|
||||
src = NULL;
|
||||
}
|
||||
|
21
src/physics.h
Normal file
21
src/physics.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "def.h"
|
||||
|
||||
// Base of 2D vectors.
|
||||
typedef struct {
|
||||
FP x, y; // Basic 2D vector components.
|
||||
} Vec2;
|
||||
|
||||
// Describe any solid in 2D space.
|
||||
struct Solid {
|
||||
FP mass, force, dir; // Properties.
|
||||
Vec2 vel, pos; // Position/velocity vectors.
|
||||
void(*update)(struct Solid*, const FP); // Update method.
|
||||
};
|
||||
|
||||
typedef struct Solid Solid;
|
||||
|
||||
void solid_init(Solid* dest, const FP mass, const Vec2* vel, const Vec2* pos);
|
||||
Solid* solid_create(const FP mass, const Vec2* vel, const Vec2* pos);
|
||||
void solid_free(Solid* src);
|
||||
|
80
src/pilot.c
Normal file
80
src/pilot.c
Normal file
@ -0,0 +1,80 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "pilot.h"
|
||||
|
||||
// Stack of pilot id's to assure uniqueness.
|
||||
static unsigned int pilot_id = 0;
|
||||
|
||||
static void pilot_update(Pilot* pilot, const FP dt);
|
||||
static void pilot_render(Pilot* pilot);
|
||||
|
||||
// Render the pilot.
|
||||
static void pilot_render(Pilot* pilot) {
|
||||
int sprite;
|
||||
Vec2 pos;
|
||||
gl_texture* texture = pilot->ship->gfx_ship;
|
||||
|
||||
pos.x = pilot->solid->pos.x;
|
||||
pos.y = pilot->solid->pos.y;
|
||||
|
||||
// Get the sprite corresponding to the direction facing.
|
||||
sprite = (int)(pilot->solid->dir / (2.0*M_PI / (texture->sy * texture->sx)));
|
||||
|
||||
gl_blitSprite(texture, &pos, sprite % (int)texture->sx, sprite / (int)texture->sy);
|
||||
}
|
||||
|
||||
// Update the pilot.
|
||||
static void pilot_update(Pilot* pilot, const FP dt) {
|
||||
if(pilot->solid->dir > 2*M_PI) pilot->solid->dir -= 2*M_PI;
|
||||
if(pilot->solid->dir < 0.0) pilot->solid->dir += 2*M_PI;
|
||||
|
||||
// Update the solid.
|
||||
pilot->solid->update(pilot->solid, dt);
|
||||
|
||||
pilot_render(pilot);
|
||||
}
|
||||
|
||||
// ==Init pilot.===========================================
|
||||
// ship : Ship pilot is flying.
|
||||
// name : Pilot's name, if NULL, ships name will be used.
|
||||
// vel : Initial velocity.
|
||||
// pos : Initial position.
|
||||
// flags : Tweaking the pilot.
|
||||
// ========================================================
|
||||
void pilot_init(Pilot* pilot, Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags) {
|
||||
pilot->id = pilot_id++; // New unique pilot id based on pilot_id.
|
||||
|
||||
pilot->ship = ship;
|
||||
if(name == NULL)
|
||||
pilot->name = ship->name;
|
||||
else
|
||||
pilot->name = name;
|
||||
|
||||
pilot->solid = solid_create(ship->mass, vel, pos);
|
||||
|
||||
pilot->armor = ship->armor;
|
||||
pilot->shield = ship->shield;
|
||||
pilot->energy = ship->energy;
|
||||
|
||||
if(flags & PILOT_PLAYER)
|
||||
pilot->think = NULL; // Players don't need to thing! :P
|
||||
|
||||
pilot->update = pilot_update;
|
||||
}
|
||||
|
||||
// Create a new pilot - Params are same as pilot_init.
|
||||
Pilot* pilot_create(Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags) {
|
||||
Pilot* dyn = MALLOC_L(Pilot);
|
||||
assert(dyn != NULL);
|
||||
pilot_init(dyn, ship, name, vel, pos, flags);
|
||||
return dyn;
|
||||
}
|
||||
|
||||
// Free the prisoned pilot!
|
||||
void pilot_free(Pilot* pilot) {
|
||||
solid_free(pilot->solid);
|
||||
free(pilot);
|
||||
pilot = NULL;
|
||||
}
|
||||
|
32
src/pilot.h
Normal file
32
src/pilot.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include "def.h"
|
||||
#include "physics.h"
|
||||
#include "ship.h"
|
||||
|
||||
#define PILOT_PLAYER 1 // Pilot is a player.
|
||||
|
||||
struct Pilot {
|
||||
int id; // Pilot's id.
|
||||
char* name; // Pilot's name (if unique).
|
||||
|
||||
Ship* ship; // Pilots ship.
|
||||
Solid* solid; // Associated solid (physics).
|
||||
|
||||
// Current health.
|
||||
FP armor, shield, energy;
|
||||
|
||||
void (*update)(struct Pilot*, const FP); // Update the pilot.
|
||||
void (*think)(struct Pilot*); // AI thinking for the pilot.
|
||||
|
||||
unsigned int flags; // Used for AI etc.
|
||||
};
|
||||
typedef struct Pilot Pilot;
|
||||
|
||||
void pilot_init(Pilot* dest, Ship* ship, char* name,
|
||||
const Vec2* vel, const Vec2* pos, const int flags);
|
||||
|
||||
Pilot* pilot_create(Ship* ship, char* name, const Vec2* vel,
|
||||
const Vec2* pos, const int flags);
|
||||
|
||||
void pilot_free(Pilot* src);
|
||||
|
2
src/ship.c
Normal file
2
src/ship.c
Normal file
@ -0,0 +1,2 @@
|
||||
#include "ship.h"
|
||||
|
30
src/ship.h
Normal file
30
src/ship.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include "def.h"
|
||||
#include "opengl.h"
|
||||
|
||||
enum ship_class { SHIP_CLASS_NULL, SHIP_CLASS_CIVILIAN };
|
||||
typedef enum ship_class ship_class;
|
||||
|
||||
typedef struct {
|
||||
char* name; // Ship name.
|
||||
ship_class class; // Ship class.
|
||||
|
||||
// Movement.
|
||||
FP thrust, turn, speed;
|
||||
|
||||
// Graphics.
|
||||
gl_texture* gfx_ship, *gfx_target;
|
||||
|
||||
// Characteristics.
|
||||
int crew;
|
||||
int mass;
|
||||
|
||||
// Health.
|
||||
FP armor, armor_regen;
|
||||
FP shield, shield_regen;
|
||||
FP energy, energy_regen;
|
||||
|
||||
// Capacity.
|
||||
int cap_cargo, cap_weapon;
|
||||
} Ship;
|
||||
|
Loading…
Reference in New Issue
Block a user