mirror of
https://github.com/libsm64/libsm64.git
synced 2025-01-22 15:43:11 -05:00
Merge pull request #26 from headshot2017/master
audio implementation on test program + many other improvements
This commit is contained in:
commit
9ae96c42f0
18 changed files with 977 additions and 488 deletions
29
Makefile
29
Makefile
|
@ -2,12 +2,14 @@ default: lib
|
|||
|
||||
ifdef LIBSM64_MUSL
|
||||
CC := musl-gcc
|
||||
CXX := musl-g++
|
||||
LDFLAGS := -lm -static -shared
|
||||
else
|
||||
CC := cc
|
||||
CXX := c++
|
||||
LDFLAGS := -lm -shared
|
||||
endif
|
||||
CFLAGS := -g -Wall -fPIC -DSM64_LIB_EXPORT -DGBI_FLOATS -DVERSION_US -DNO_SEGMENTED_MEMORY
|
||||
CFLAGS := -g -Wall -Wno-unused-function -fPIC -DSM64_LIB_EXPORT -DGBI_FLOATS -DVERSION_US -DNO_SEGMENTED_MEMORY
|
||||
|
||||
SRC_DIRS := src src/decomp src/decomp/engine src/decomp/include/PR src/decomp/game src/decomp/pc src/decomp/pc/audio src/decomp/mario src/decomp/tools src/decomp/audio
|
||||
BUILD_DIR := build
|
||||
|
@ -26,14 +28,16 @@ C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) $(C_IMPORTED)
|
|||
O_FILES := $(foreach file,$(C_FILES),$(BUILD_DIR)/$(file:.c=.o))
|
||||
DEP_FILES := $(O_FILES:.o=.d)
|
||||
|
||||
TEST_SRCS := test/main.c test/context.c test/level.c
|
||||
TEST_OBJS := $(foreach file,$(TEST_SRCS),$(BUILD_DIR)/$(file:.c=.o))
|
||||
TEST_SRCS_C := test/context.c test/level.c test/gl33core/gl33core_renderer.c test/gl20/gl20_renderer.c
|
||||
TEST_SRCS_CPP := test/main.cpp test/audio.cpp
|
||||
TEST_OBJS := $(foreach file,$(TEST_SRCS_C),$(BUILD_DIR)/$(file:.c=.o)) $(foreach file,$(TEST_SRCS_CPP),$(BUILD_DIR)/$(file:.cpp=.o))
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
LIB_FILE := $(DIST_DIR)/sm64.dll
|
||||
TEST_FILE := $(DIST_DIR)/run-test.exe
|
||||
endif
|
||||
|
||||
DUMMY != mkdir -p $(ALL_DIRS) build/test src/decomp/mario $(DIST_DIR)/include
|
||||
DUMMY != mkdir -p $(ALL_DIRS) build/test build/test/gl33core build/test/gl20 src/decomp/mario $(DIST_DIR)/include
|
||||
|
||||
|
||||
$(filter-out src/decomp/mario/geo.inc.c,$(IMPORTED)): src/decomp/mario/geo.inc.c
|
||||
|
@ -44,6 +48,10 @@ $(BUILD_DIR)/%.o: %.c $(IMPORTED)
|
|||
@$(CC) $(CFLAGS) -MM -MP -MT $@ -MF $(BUILD_DIR)/$*.d $<
|
||||
$(CC) -c $(CFLAGS) -I src/decomp/include -o $@ $<
|
||||
|
||||
$(BUILD_DIR)/%.o: %.cpp $(IMPORTED)
|
||||
@$(CXX) $(CFLAGS) -MM -MP -MT $@ -MF $(BUILD_DIR)/$*.d $<
|
||||
$(CXX) -c $(CFLAGS) -I src/decomp/include -o $@ $<
|
||||
|
||||
$(LIB_FILE): $(O_FILES)
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
|
||||
|
@ -54,22 +62,29 @@ $(LIB_H_FILE): src/libsm64.h
|
|||
test/level.c test/level.h: ./import-test-collision.py
|
||||
./import-test-collision.py
|
||||
|
||||
test/main.c: test/level.h
|
||||
test/main.cpp: test/level.h
|
||||
|
||||
$(BUILD_DIR)/test/%.o: test/%.c
|
||||
@$(CC) $(CFLAGS) -MM -MP -MT $@ -MF $(BUILD_DIR)/test/$*.d $<
|
||||
$(CC) -c $(CFLAGS) -o $@ $<
|
||||
|
||||
$(TEST_FILE): $(LIB_FILE) $(TEST_OBJS)
|
||||
$(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lGLEW -lGL -lSDL2 -lSDL2main -lm
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
$(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lglew32 -lopengl32 -lSDL2 -lSDL2main -lm
|
||||
else
|
||||
$(CC) -o $@ $(TEST_OBJS) $(LIB_FILE) -lGLEW -lGL -lSDL2 -lSDL2main -lm -lpthread
|
||||
endif
|
||||
|
||||
lib: $(LIB_FILE) $(LIB_H_FILE)
|
||||
|
||||
test: $(TEST_FILE) $(LIB_H_FILE)
|
||||
|
||||
run: test
|
||||
ifeq ($(OS),Windows_NT)
|
||||
cd dist && ./run-test
|
||||
else
|
||||
./$(TEST_FILE)
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR) $(DIST_DIR) $(TEST_FILE)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "../include/sm64.h"
|
||||
|
||||
#include "area.h"
|
||||
// #include "audio/external.h"
|
||||
#include "../audio/external.h"
|
||||
// #include "behavior_actions.h"
|
||||
// #include "behavior_data.h"
|
||||
#include "camera.h"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "../include/sm64.h"
|
||||
#include "area.h"
|
||||
//#include "audio/external.h"
|
||||
#include "../audio/external.h"
|
||||
#include "camera.h"
|
||||
#include "../engine/graph_node.h"
|
||||
#include "../engine/math_util.h"
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
//#include "prevent_bss_reordering.h"
|
||||
#include "../include/sm64.h"
|
||||
#include "area.h"
|
||||
//#include "audio/external.h"
|
||||
#include "../audio/external.h"
|
||||
//#include "behavior_data.h"
|
||||
#include "camera.h"
|
||||
//#include "dialog_ids.h"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "../include/sm64.h"
|
||||
#include "area.h"
|
||||
//#include "audio/external.h"
|
||||
#include "../audio/external.h"
|
||||
//#include "behavior_data.h"
|
||||
#include "camera.h"
|
||||
#include "../engine/math_util.h"
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#define gSpecialTripleJump (g_state->mgSpecialTripleJump)
|
||||
#define gCurrLevelNum (g_state->mgCurrLevelNum)
|
||||
#define gCameraMovementFlags (g_state->mgCameraMovementFlags)
|
||||
#define gAudioRandom (g_state->mgAudioRandom)
|
||||
//#define gAudioRandom (g_state->mgAudioRandom)
|
||||
#define gShowDebugText (g_state->mgShowDebugText)
|
||||
#define gDebugLevelSelect (g_state->mgDebugLevelSelect)
|
||||
#define gCurrSaveFileNum (g_state->mgCurrSaveFileNum)
|
||||
|
|
|
@ -228,6 +228,10 @@ SM64_LIB_FN void sm64_mario_tick( int32_t marioId, const struct SM64MarioInputs
|
|||
update_button( inputs->buttonB, B_BUTTON );
|
||||
update_button( inputs->buttonZ, Z_TRIG );
|
||||
|
||||
gMarioState->marioObj->header.gfx.cameraToObject[0] = 0;
|
||||
gMarioState->marioObj->header.gfx.cameraToObject[1] = 0;
|
||||
gMarioState->marioObj->header.gfx.cameraToObject[2] = 0;
|
||||
|
||||
gMarioState->area->camera->yaw = atan2s( inputs->camLookZ, inputs->camLookX );
|
||||
|
||||
gController.stickX = -64.0f * inputs->stickX;
|
||||
|
|
77
test/audio.cpp
Normal file
77
test/audio.cpp
Normal file
|
@ -0,0 +1,77 @@
|
|||
#include "audio.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
extern "C" {
|
||||
#include "../src/libsm64.h"
|
||||
#include "context.h"
|
||||
}
|
||||
|
||||
static SDL_AudioDeviceID dev;
|
||||
|
||||
pthread_t gSoundThread;
|
||||
long long timeInMilliseconds(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
return(((long long)tv.tv_sec)*1000)+(tv.tv_usec/1000);
|
||||
}
|
||||
|
||||
void* audio_thread(void* keepAlive)
|
||||
{
|
||||
// from https://github.com/ckosmic/libsm64/blob/audio/src/libsm64.c#L535-L555
|
||||
// except keepAlive is a null pointer here, so don't use it
|
||||
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
|
||||
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
|
||||
|
||||
long long currentTime = timeInMilliseconds();
|
||||
long long targetTime = 0;
|
||||
while(1)
|
||||
{
|
||||
//if(!*((bool*)keepAlive)) return NULL;
|
||||
|
||||
int16_t audioBuffer[544 * 2 * 2];
|
||||
uint32_t numSamples = sm64_audio_tick(SDL_GetQueuedAudioSize(dev)/4, 1100, audioBuffer);
|
||||
if (SDL_GetQueuedAudioSize(dev)/4 < 6000)
|
||||
SDL_QueueAudio(dev, audioBuffer, numSamples * 2 * 4);
|
||||
|
||||
targetTime = currentTime + 33;
|
||||
while (timeInMilliseconds() < targetTime)
|
||||
{
|
||||
usleep(100);
|
||||
//if(!*((bool*)keepAlive)) return NULL;
|
||||
}
|
||||
currentTime = timeInMilliseconds();
|
||||
}
|
||||
}
|
||||
|
||||
void audio_init()
|
||||
{
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
fprintf(stderr, "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_AudioSpec want, have;
|
||||
SDL_zero(want);
|
||||
want.freq = 32000;
|
||||
want.format = AUDIO_S16;
|
||||
want.channels = 2;
|
||||
want.samples = 512;
|
||||
want.callback = NULL;
|
||||
dev = SDL_OpenAudioDevice(NULL, 0, &want, &have, 0);
|
||||
if (dev == 0) {
|
||||
fprintf(stderr, "SDL_OpenAudio error: %s\n", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
SDL_PauseAudioDevice(dev, 0);
|
||||
|
||||
// it's best to run audio in a separate thread
|
||||
pthread_create(&gSoundThread, NULL, audio_thread, NULL);
|
||||
}
|
||||
|
6
test/audio.h
Normal file
6
test/audio.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
void audio_init();
|
||||
|
||||
#endif
|
|
@ -5,23 +5,21 @@
|
|||
static SDL_Window *s_sdlWindow;
|
||||
static SDL_GLContext s_sdlGlContext;
|
||||
static SDL_GameController *s_controller;
|
||||
static int s_windowWidth;
|
||||
static int s_windowHeight;
|
||||
int WINDOW_WIDTH;
|
||||
int WINDOW_HEIGHT;
|
||||
|
||||
void context_init( const char *title, int width, int height )
|
||||
void context_init( const char *title, int width, int height, int major, int minor )
|
||||
{
|
||||
if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0 ) goto err;
|
||||
|
||||
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
|
||||
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 4 );
|
||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 4 );
|
||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
|
||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
|
||||
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
||||
SDL_GL_SetSwapInterval( 1 );
|
||||
int profile = (major < 3) ? SDL_GL_CONTEXT_PROFILE_COMPATIBILITY : SDL_GL_CONTEXT_PROFILE_CORE;
|
||||
|
||||
s_windowWidth = width;
|
||||
s_windowHeight = height;
|
||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, major );
|
||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, minor );
|
||||
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, profile );
|
||||
|
||||
WINDOW_WIDTH = width;
|
||||
WINDOW_HEIGHT = height;
|
||||
|
||||
s_sdlWindow = SDL_CreateWindow(
|
||||
title,
|
||||
|
@ -33,6 +31,7 @@ void context_init( const char *title, int width, int height )
|
|||
if( !s_sdlWindow ) goto err;
|
||||
|
||||
s_sdlGlContext = SDL_GL_CreateContext( s_sdlWindow );
|
||||
SDL_GL_SetSwapInterval( 1 );
|
||||
|
||||
if( !s_sdlGlContext ) goto err;
|
||||
|
||||
|
@ -88,9 +87,9 @@ bool context_flip_frame_poll_events( void )
|
|||
case SDL_WINDOWEVENT:
|
||||
if( event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED )
|
||||
{
|
||||
s_windowWidth = event.window.data1;
|
||||
s_windowHeight = event.window.data2;
|
||||
glViewport( 0, 0, s_windowWidth, s_windowHeight );
|
||||
WINDOW_WIDTH = event.window.data1;
|
||||
WINDOW_HEIGHT = event.window.data2;
|
||||
glViewport( 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -112,4 +111,4 @@ void context_terminate( void )
|
|||
SDL_Quit();
|
||||
|
||||
s_sdlWindow = NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,16 @@
|
|||
#elif _WIN32
|
||||
# define HAVE_M_PI
|
||||
# include <GL/glew.h>
|
||||
# include <SDL.h>
|
||||
# include <SDL2/SDL.h>
|
||||
#else
|
||||
# include <GL/glew.h>
|
||||
# include <SDL2/SDL.h>
|
||||
#endif
|
||||
|
||||
extern void context_init( const char *title, int width, int height );
|
||||
extern int WINDOW_WIDTH;
|
||||
extern int WINDOW_HEIGHT;
|
||||
|
||||
extern void context_init( const char *title, int width, int height, int major, int minor );
|
||||
extern bool context_flip_frame_poll_events( void );
|
||||
extern SDL_GameController *context_get_controller( void );
|
||||
extern void context_terminate( void );
|
227
test/gl20/gl20_renderer.c
Normal file
227
test/gl20/gl20_renderer.c
Normal file
|
@ -0,0 +1,227 @@
|
|||
#include "gl20_renderer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../src/libsm64.h"
|
||||
#include "../renderer.h"
|
||||
#include "../context.h"
|
||||
#include "../level.h"
|
||||
|
||||
GLuint worldTexture;
|
||||
uint8_t *worldTextureRaw;
|
||||
int worldTextureSize[2] = {256, 256};
|
||||
float *worldUv;
|
||||
|
||||
static void load_collision_mesh( CollisionMesh *mesh )
|
||||
{
|
||||
mesh->num_vertices = 3 * surfaces_count;
|
||||
mesh->position = malloc( sizeof( float ) * surfaces_count * 9 );
|
||||
mesh->normal = malloc( sizeof( float ) * surfaces_count * 9 );
|
||||
mesh->color = malloc( sizeof( float ) * surfaces_count * 9 );
|
||||
worldUv = malloc(sizeof(float) * surfaces_count * 6);
|
||||
mesh->index = malloc( sizeof( uint16_t ) * surfaces_count * 3 );
|
||||
|
||||
for( size_t i = 0; i < surfaces_count; ++i )
|
||||
{
|
||||
const struct SM64Surface *surf = &surfaces[i];
|
||||
|
||||
float x1 = mesh->position[9*i+0] = surf->vertices[0][0];
|
||||
float y1 = mesh->position[9*i+1] = surf->vertices[0][1];
|
||||
float z1 = mesh->position[9*i+2] = surf->vertices[0][2];
|
||||
float x2 = mesh->position[9*i+3] = surf->vertices[1][0];
|
||||
float y2 = mesh->position[9*i+4] = surf->vertices[1][1];
|
||||
float z2 = mesh->position[9*i+5] = surf->vertices[1][2];
|
||||
float x3 = mesh->position[9*i+6] = surf->vertices[2][0];
|
||||
float y3 = mesh->position[9*i+7] = surf->vertices[2][1];
|
||||
float z3 = mesh->position[9*i+8] = surf->vertices[2][2];
|
||||
|
||||
float nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2);
|
||||
float ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2);
|
||||
float nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
|
||||
float mag = sqrtf(nx * nx + ny * ny + nz * nz);
|
||||
nx /= mag;
|
||||
ny /= mag;
|
||||
nz /= mag;
|
||||
|
||||
mesh->normal[9*i+0] = nx;
|
||||
mesh->normal[9*i+1] = ny;
|
||||
mesh->normal[9*i+2] = nz;
|
||||
mesh->normal[9*i+3] = nx;
|
||||
mesh->normal[9*i+4] = ny;
|
||||
mesh->normal[9*i+5] = nz;
|
||||
mesh->normal[9*i+6] = nx;
|
||||
mesh->normal[9*i+7] = ny;
|
||||
mesh->normal[9*i+8] = nz;
|
||||
|
||||
for (int j=0; j<9; j++)
|
||||
mesh->color[9*i+j] = (0.5 + 0.25 * 1) * (.5+.5*mesh->normal[9*i+j]);
|
||||
|
||||
mesh->index[3*i+0] = 3*i+0;
|
||||
mesh->index[3*i+1] = 3*i+1;
|
||||
mesh->index[3*i+2] = 3*i+2;
|
||||
}
|
||||
|
||||
for( size_t i = 0; i < surfaces_count/2; i++ )
|
||||
{
|
||||
worldUv[12*i+0] = 0.f;
|
||||
worldUv[12*i+1] = 0.f;
|
||||
worldUv[12*i+2] = 4.f;
|
||||
worldUv[12*i+3] = 0.f;
|
||||
worldUv[12*i+4] = 0.f;
|
||||
worldUv[12*i+5] = 4.f;
|
||||
|
||||
worldUv[12*i+6] = 0.f;
|
||||
worldUv[12*i+7] = 4.f;
|
||||
worldUv[12*i+8] = 4.f;
|
||||
worldUv[12*i+9] = 0.f;
|
||||
worldUv[12*i+10] = 0.f;
|
||||
worldUv[12*i+11] = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo )
|
||||
{
|
||||
mesh->index = malloc( 3 * SM64_GEO_MAX_TRIANGLES * sizeof(uint16_t) );
|
||||
for( int i = 0; i < 3 * SM64_GEO_MAX_TRIANGLES; ++i )
|
||||
mesh->index[i] = i;
|
||||
|
||||
mesh->num_vertices = 3 * SM64_GEO_MAX_TRIANGLES;
|
||||
}
|
||||
|
||||
static void update_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo )
|
||||
{
|
||||
if( mesh->index == NULL )
|
||||
load_mario_mesh( mesh, marioGeo );
|
||||
|
||||
mesh->num_vertices = 3 * marioGeo->numTrianglesUsed;
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, 0, marioGeo->position);
|
||||
glNormalPointer(GL_FLOAT, 0, marioGeo->normal);
|
||||
glColorPointer(3, GL_FLOAT, 0, marioGeo->color);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, marioGeo->uv);
|
||||
}
|
||||
|
||||
static void gl20_init(RenderState *renderState, uint8_t *marioTexture)
|
||||
{
|
||||
load_collision_mesh( &renderState->collision );
|
||||
|
||||
glEnable( GL_CULL_FACE );
|
||||
glCullFace( GL_BACK );
|
||||
glClearColor( 0.2f, 0.2f, 0.2f, 1.0f );
|
||||
glDepthMask( GL_TRUE );
|
||||
glDepthFunc( GL_LEQUAL );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||||
glEnable( GL_BLEND );
|
||||
glColor4f(1,1,1,1);
|
||||
|
||||
glGenTextures( 1, &renderState->mario_texture );
|
||||
glBindTexture( GL_TEXTURE_2D, renderState->mario_texture );
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SM64_TEXTURE_WIDTH, SM64_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, marioTexture);
|
||||
|
||||
// make a custom world texture programatically
|
||||
worldTextureRaw = (uint8_t*)malloc(worldTextureSize[0] * worldTextureSize[1] * 4);
|
||||
memset(worldTextureRaw, 255, worldTextureSize[0] * worldTextureSize[1] * 4);
|
||||
|
||||
for (int y=0; y<worldTextureSize[1]/2; y++)
|
||||
{
|
||||
for (int x = worldTextureSize[1]/2 - (y+1); x<worldTextureSize[1]/2 + (y+1); x++)
|
||||
{
|
||||
int i1 = y * worldTextureSize[0] + x;
|
||||
int i2 = (worldTextureSize[1]-1-y) * worldTextureSize[0] + x;
|
||||
worldTextureRaw[i1*4+0] = 192;
|
||||
worldTextureRaw[i1*4+1] = 192;
|
||||
worldTextureRaw[i1*4+2] = 192;
|
||||
worldTextureRaw[i2*4+0] = 192;
|
||||
worldTextureRaw[i2*4+1] = 192;
|
||||
worldTextureRaw[i2*4+2] = 192;
|
||||
}
|
||||
}
|
||||
|
||||
glGenTextures(1, &worldTexture );
|
||||
glBindTexture(GL_TEXTURE_2D, worldTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, worldTextureSize[0], worldTextureSize[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, worldTextureRaw);
|
||||
}
|
||||
|
||||
static void gl20_draw(RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo)
|
||||
{
|
||||
mat4 model, view, projection;
|
||||
glm_perspective( 45.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 100.0f, 20000.0f, projection );
|
||||
glm_translate( view, (float*)camPos );
|
||||
glm_lookat( (float*)camPos, (float*)marioState->position, (vec3){0,1,0}, view );
|
||||
glm_mat4_identity( model );
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadMatrixf((GLfloat*)projection);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadMatrixf((GLfloat*)view);
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
// draw world
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_NORMAL_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, 0, renderState->collision.position);
|
||||
glNormalPointer(GL_FLOAT, 0, renderState->collision.normal);
|
||||
glColorPointer(3, GL_FLOAT, 0, renderState->collision.color);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, worldUv);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, worldTexture);
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glDrawElements(GL_TRIANGLES, renderState->collision.num_vertices, GL_UNSIGNED_SHORT, renderState->collision.index);
|
||||
|
||||
// create lighting on the scene
|
||||
GLfloat light_position[] = { camPos[0], camPos[1], camPos[2], 1 };
|
||||
GLfloat light_diffuse[] = { 0.6f, 0.6f, 0.6f, 1 };
|
||||
GLfloat light_model[] = { 0.5f, 0.5f, 0.5f, 1 };
|
||||
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
|
||||
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
|
||||
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_model);
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glEnable(GL_COLOR_MATERIAL);
|
||||
glEnable(GL_LIGHTING);
|
||||
glEnable(GL_LIGHT0);
|
||||
|
||||
// first, draw geometry without Mario's texture.
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
update_mario_mesh( &renderState->mario, marioGeo );
|
||||
uint32_t triangleSize = renderState->mario.num_vertices;
|
||||
|
||||
glDrawElements(GL_TRIANGLES, triangleSize, GL_UNSIGNED_SHORT, renderState->mario.index);
|
||||
|
||||
// now disable the color array and enable the texture.
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glBindTexture(GL_TEXTURE_2D, renderState->mario_texture);
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
|
||||
glDrawElements(GL_TRIANGLES, triangleSize, GL_UNSIGNED_SHORT, renderState->mario.index);
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisable(GL_LIGHTING);
|
||||
}
|
||||
|
||||
struct Renderer gl20_renderer = {
|
||||
gl20_init,
|
||||
gl20_draw
|
||||
};
|
6
test/gl20/gl20_renderer.h
Normal file
6
test/gl20/gl20_renderer.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef GL20_RENDERER_H
|
||||
#define GL20_RENDERER_H
|
||||
|
||||
extern struct Renderer gl20_renderer;
|
||||
|
||||
#endif
|
313
test/gl33core/gl33core_renderer.c
Normal file
313
test/gl33core/gl33core_renderer.c
Normal file
|
@ -0,0 +1,313 @@
|
|||
#include "gl33core_renderer.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../src/libsm64.h"
|
||||
#include "../renderer.h"
|
||||
#include "../context.h"
|
||||
#include "../cglm.h"
|
||||
#include "../level.h"
|
||||
|
||||
static const char *MARIO_SHADER =
|
||||
"\n uniform mat4 view;"
|
||||
"\n uniform mat4 projection;"
|
||||
"\n uniform sampler2D marioTex;"
|
||||
"\n "
|
||||
"\n v2f vec3 v_color;"
|
||||
"\n v2f vec3 v_normal;"
|
||||
"\n v2f vec3 v_light;"
|
||||
"\n v2f vec2 v_uv;"
|
||||
"\n "
|
||||
"\n #ifdef VERTEX"
|
||||
"\n "
|
||||
"\n layout(location = 0) in vec3 position;"
|
||||
"\n layout(location = 1) in vec3 normal;"
|
||||
"\n layout(location = 2) in vec3 color;"
|
||||
"\n layout(location = 3) in vec2 uv;"
|
||||
"\n "
|
||||
"\n void main()"
|
||||
"\n {"
|
||||
"\n v_color = color;"
|
||||
"\n v_normal = normal;"
|
||||
"\n v_light = transpose( mat3( view )) * normalize( vec3( 1 ));"
|
||||
"\n v_uv = uv;"
|
||||
"\n "
|
||||
"\n gl_Position = projection * view * vec4( position, 1. );"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
"\n #ifdef FRAGMENT"
|
||||
"\n "
|
||||
"\n out vec4 color;"
|
||||
"\n "
|
||||
"\n void main() "
|
||||
"\n {"
|
||||
"\n float light = .5 + .5 * clamp( dot( v_normal, v_light ), 0., 1. );"
|
||||
"\n vec4 texColor = texture2D( marioTex, v_uv );"
|
||||
"\n vec3 mainColor = mix( v_color, texColor.rgb, texColor.a ); // v_uv.x >= 0. ? texColor.a : 0. );"
|
||||
"\n color = vec4( mainColor * light, 1 );"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
;
|
||||
static const char *WORLD_SHADER =
|
||||
"\n uniform mat4 model;"
|
||||
"\n uniform mat4 view;"
|
||||
"\n uniform mat4 projection;"
|
||||
"\n uniform sampler2D tex;"
|
||||
"\n "
|
||||
"\n v2f vec3 v_normal;"
|
||||
"\n v2f vec3 v_worldPos;"
|
||||
"\n "
|
||||
"\n #ifdef VERTEX"
|
||||
"\n "
|
||||
"\n layout(location = 0) in vec3 position;"
|
||||
"\n layout(location = 1) in vec3 normal;"
|
||||
"\n "
|
||||
"\n void main()"
|
||||
"\n {"
|
||||
"\n v_normal = inverse(mat3(model)) * normal;"
|
||||
"\n vec4 worldPos4 = model * vec4(position, 1.);"
|
||||
"\n v_worldPos = worldPos4.xyz;"
|
||||
"\n gl_Position = projection * view * worldPos4;"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
"\n #ifdef FRAGMENT"
|
||||
"\n "
|
||||
"\n vec3 tri( vec3 x )"
|
||||
"\n {"
|
||||
"\n return abs(x-floor(x)-.5);"
|
||||
"\n } "
|
||||
"\n float surfFunc( vec3 p )"
|
||||
"\n {"
|
||||
"\n float n = dot(tri(p*.15 + tri(p.yzx*.075)), vec3(.444));"
|
||||
"\n p = p*1.5773 - n;"
|
||||
"\n p.yz = vec2(p.y + p.z, p.z - p.y) * .866;"
|
||||
"\n p.xz = vec2(p.x + p.z, p.z - p.x) * .866;"
|
||||
"\n n += dot(tri(p*.225 + tri(p.yzx*.1125)), vec3(.222)); "
|
||||
"\n return abs(n-.5)*1.9 + (1.-abs(sin(n*9.)))*.05;"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n const vec3 light_x = vec3(-1.0, 0.4, 0.9);"
|
||||
"\n "
|
||||
"\n out vec4 color;"
|
||||
"\n "
|
||||
"\n void main() "
|
||||
"\n {"
|
||||
"\n float surfy = surfFunc( v_worldPos / 50. );"
|
||||
"\n float brightness = smoothstep( .2, .3, surfy );"
|
||||
"\n "
|
||||
"\n color = vec4( (0.5 + 0.25 * brightness) * (.5+.5*v_normal), 1 );"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
;
|
||||
|
||||
static void load_collision_mesh( CollisionMesh *mesh )
|
||||
{
|
||||
mesh->num_vertices = 3 * surfaces_count;
|
||||
mesh->position = malloc( sizeof( float ) * surfaces_count * 9 );
|
||||
mesh->normal = malloc( sizeof( float ) * surfaces_count * 9 );
|
||||
mesh->index = malloc( sizeof( uint16_t ) * surfaces_count * 3 );
|
||||
|
||||
for( size_t i = 0; i < surfaces_count; ++i )
|
||||
{
|
||||
const struct SM64Surface *surf = &surfaces[i];
|
||||
|
||||
float x1 = mesh->position[9*i+0] = surf->vertices[0][0];
|
||||
float y1 = mesh->position[9*i+1] = surf->vertices[0][1];
|
||||
float z1 = mesh->position[9*i+2] = surf->vertices[0][2];
|
||||
float x2 = mesh->position[9*i+3] = surf->vertices[1][0];
|
||||
float y2 = mesh->position[9*i+4] = surf->vertices[1][1];
|
||||
float z2 = mesh->position[9*i+5] = surf->vertices[1][2];
|
||||
float x3 = mesh->position[9*i+6] = surf->vertices[2][0];
|
||||
float y3 = mesh->position[9*i+7] = surf->vertices[2][1];
|
||||
float z3 = mesh->position[9*i+8] = surf->vertices[2][2];
|
||||
|
||||
float nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2);
|
||||
float ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2);
|
||||
float nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
|
||||
float mag = sqrtf(nx * nx + ny * ny + nz * nz);
|
||||
nx /= mag;
|
||||
ny /= mag;
|
||||
nz /= mag;
|
||||
|
||||
mesh->normal[9*i+0] = nx;
|
||||
mesh->normal[9*i+1] = ny;
|
||||
mesh->normal[9*i+2] = nz;
|
||||
mesh->normal[9*i+3] = nx;
|
||||
mesh->normal[9*i+4] = ny;
|
||||
mesh->normal[9*i+5] = nz;
|
||||
mesh->normal[9*i+6] = nx;
|
||||
mesh->normal[9*i+7] = ny;
|
||||
mesh->normal[9*i+8] = nz;
|
||||
|
||||
mesh->index[3*i+0] = 3*i+0;
|
||||
mesh->index[3*i+1] = 3*i+1;
|
||||
mesh->index[3*i+2] = 3*i+2;
|
||||
}
|
||||
|
||||
glGenVertexArrays( 1, &mesh->vao );
|
||||
glBindVertexArray( mesh->vao );
|
||||
|
||||
#define X( loc, buff, arr, type ) do { \
|
||||
glGenBuffers( 1, &buff ); \
|
||||
glBindBuffer( GL_ARRAY_BUFFER, buff ); \
|
||||
glBufferData( GL_ARRAY_BUFFER, mesh->num_vertices*sizeof( type ), arr, GL_STATIC_DRAW ); \
|
||||
glEnableVertexAttribArray( loc ); \
|
||||
glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \
|
||||
} while( 0 )
|
||||
|
||||
X( 0, mesh->position_buffer, mesh->position, vec3 );
|
||||
X( 1, mesh->normal_buffer, mesh->normal, vec3 );
|
||||
|
||||
#undef X
|
||||
}
|
||||
|
||||
static void load_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo )
|
||||
{
|
||||
mesh->index = malloc( 3 * SM64_GEO_MAX_TRIANGLES * sizeof(uint16_t) );
|
||||
for( int i = 0; i < 3 * SM64_GEO_MAX_TRIANGLES; ++i )
|
||||
mesh->index[i] = i;
|
||||
|
||||
mesh->num_vertices = 3 * SM64_GEO_MAX_TRIANGLES;
|
||||
|
||||
glGenVertexArrays( 1, &mesh->vao );
|
||||
glBindVertexArray( mesh->vao );
|
||||
|
||||
#define X( loc, buff, arr, type ) do { \
|
||||
glGenBuffers( 1, &buff ); \
|
||||
glBindBuffer( GL_ARRAY_BUFFER, buff ); \
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( type ) * 3 * SM64_GEO_MAX_TRIANGLES, arr, GL_DYNAMIC_DRAW ); \
|
||||
glEnableVertexAttribArray( loc ); \
|
||||
glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \
|
||||
} while( 0 )
|
||||
|
||||
X( 0, mesh->position_buffer, marioGeo->position, vec3 );
|
||||
X( 1, mesh->normal_buffer, marioGeo->normal, vec3 );
|
||||
X( 2, mesh->color_buffer, marioGeo->color, vec3 );
|
||||
X( 3, mesh->uv_buffer, marioGeo->uv, vec2 );
|
||||
|
||||
#undef X
|
||||
}
|
||||
|
||||
static void update_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo )
|
||||
{
|
||||
if( mesh->index == NULL )
|
||||
load_mario_mesh( mesh, marioGeo );
|
||||
|
||||
mesh->num_vertices = 3 * marioGeo->numTrianglesUsed;
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->position_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->position, GL_DYNAMIC_DRAW );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->normal_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->normal, GL_DYNAMIC_DRAW );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->color_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->color, GL_DYNAMIC_DRAW );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->uv_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec2 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->uv, GL_DYNAMIC_DRAW );
|
||||
}
|
||||
|
||||
static GLuint shader_compile( const char *shaderContents, size_t shaderContentsLength, GLenum shaderType )
|
||||
{
|
||||
const GLchar *shaderDefine = shaderType == GL_VERTEX_SHADER
|
||||
? "\n#version 330\n#define VERTEX \n#define v2f out\n"
|
||||
: "\n#version 330\n#define FRAGMENT\n#define v2f in \n";
|
||||
|
||||
const GLchar *shaderStrings[2] = { shaderDefine, shaderContents };
|
||||
GLint shaderStringLengths[2] = { strlen( shaderDefine ), (GLint)shaderContentsLength };
|
||||
|
||||
GLuint shader = glCreateShader( shaderType );
|
||||
glShaderSource( shader, 2, shaderStrings, shaderStringLengths );
|
||||
glCompileShader( shader );
|
||||
|
||||
GLint isCompiled;
|
||||
glGetShaderiv( shader, GL_COMPILE_STATUS, &isCompiled );
|
||||
if( isCompiled == GL_FALSE )
|
||||
{
|
||||
GLint maxLength;
|
||||
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &maxLength );
|
||||
char *log = (char*)malloc( maxLength );
|
||||
glGetShaderInfoLog( shader, maxLength, &maxLength, log );
|
||||
|
||||
printf( "Error in shader: %s\n%s\n%s\n", log, shaderStrings[0], shaderStrings[1] );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
static GLuint shader_load( const char *shaderContents )
|
||||
{
|
||||
GLuint result;
|
||||
GLuint vert = shader_compile( shaderContents, strlen( shaderContents ), GL_VERTEX_SHADER );
|
||||
GLuint frag = shader_compile( shaderContents, strlen( shaderContents ), GL_FRAGMENT_SHADER );
|
||||
|
||||
GLuint ref = glCreateProgram();
|
||||
glAttachShader( ref, vert );
|
||||
glAttachShader( ref, frag );
|
||||
|
||||
glLinkProgram ( ref );
|
||||
glDetachShader( ref, vert );
|
||||
glDetachShader( ref, frag );
|
||||
result = ref;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void gl33core_init(RenderState *renderState, uint8_t *marioTexture)
|
||||
{
|
||||
load_collision_mesh( &renderState->collision );
|
||||
renderState->world_shader = shader_load( WORLD_SHADER );
|
||||
renderState->mario_shader = shader_load( MARIO_SHADER );
|
||||
|
||||
glEnable( GL_CULL_FACE );
|
||||
glCullFace( GL_BACK );
|
||||
glClearColor( 0.2f, 0.2f, 0.2f, 1.0f );
|
||||
glDepthMask( GL_TRUE );
|
||||
glDepthFunc( GL_LEQUAL );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
|
||||
glGenTextures( 1, &renderState->mario_texture );
|
||||
glBindTexture( GL_TEXTURE_2D, renderState->mario_texture );
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SM64_TEXTURE_WIDTH, SM64_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, marioTexture);
|
||||
}
|
||||
|
||||
static void gl33core_draw(RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo)
|
||||
{
|
||||
update_mario_mesh( &renderState->mario, marioGeo );
|
||||
|
||||
mat4 model, view, projection;
|
||||
glm_perspective( 45.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 100.0f, 20000.0f, projection );
|
||||
glm_translate( view, (float*)camPos );
|
||||
glm_lookat( (float*)camPos, (float*)marioState->position, (vec3){0,1,0}, view );
|
||||
glm_mat4_identity( model );
|
||||
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
glUseProgram( renderState->world_shader );
|
||||
glBindVertexArray( renderState->collision.vao );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "model" ), 1, GL_FALSE, (GLfloat*)model );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "view" ), 1, GL_FALSE, (GLfloat*)view );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection );
|
||||
glDrawElements( GL_TRIANGLES, renderState->collision.num_vertices, GL_UNSIGNED_SHORT, renderState->collision.index );
|
||||
|
||||
glUseProgram( renderState->mario_shader );
|
||||
glActiveTexture( GL_TEXTURE0 );
|
||||
glBindTexture( GL_TEXTURE_2D, renderState->mario_texture );
|
||||
glBindVertexArray( renderState->mario.vao );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "view" ), 1, GL_FALSE, (GLfloat*)view );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection );
|
||||
glUniform1i( glGetUniformLocation( renderState->mario_shader, "marioTex" ), 0 );
|
||||
glDrawElements( GL_TRIANGLES, renderState->mario.num_vertices, GL_UNSIGNED_SHORT, renderState->mario.index );
|
||||
}
|
||||
|
||||
struct Renderer gl33core_renderer = {
|
||||
gl33core_init,
|
||||
gl33core_draw
|
||||
};
|
6
test/gl33core/gl33core_renderer.h
Normal file
6
test/gl33core/gl33core_renderer.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#ifndef GL33CORE_RENDERER_H
|
||||
#define GL33CORE_RENDERER_H
|
||||
|
||||
extern struct Renderer gl33core_renderer;
|
||||
|
||||
#endif
|
458
test/main.c
458
test/main.c
|
@ -1,458 +0,0 @@
|
|||
#define _CRT_SECURE_NO_WARNINGS 1 // for fopen
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../src/libsm64.h"
|
||||
|
||||
#include "cglm.h"
|
||||
#include "ns_clock.h"
|
||||
#include "level.h"
|
||||
#include "context.h"
|
||||
|
||||
static const int WINDOW_WIDTH = 1280;
|
||||
static const int WINDOW_HEIGHT = 800;
|
||||
|
||||
typedef struct CollisionMesh
|
||||
{
|
||||
size_t num_vertices;
|
||||
float *position;
|
||||
float *normal;
|
||||
uint16_t *index;
|
||||
|
||||
GLuint vao;
|
||||
GLuint position_buffer;
|
||||
GLuint normal_buffer;
|
||||
}
|
||||
CollisionMesh;
|
||||
|
||||
typedef struct MarioMesh
|
||||
{
|
||||
size_t num_vertices;
|
||||
uint16_t *index;
|
||||
|
||||
GLuint vao;
|
||||
GLuint position_buffer;
|
||||
GLuint normal_buffer;
|
||||
GLuint color_buffer;
|
||||
GLuint uv_buffer;
|
||||
}
|
||||
MarioMesh;
|
||||
|
||||
typedef struct RenderState
|
||||
{
|
||||
CollisionMesh collision;
|
||||
MarioMesh mario;
|
||||
GLuint world_shader;
|
||||
GLuint mario_shader;
|
||||
GLuint mario_texture;
|
||||
}
|
||||
RenderState;
|
||||
|
||||
static const char *MARIO_SHADER =
|
||||
"\n uniform mat4 view;"
|
||||
"\n uniform mat4 projection;"
|
||||
"\n uniform sampler2D marioTex;"
|
||||
"\n "
|
||||
"\n v2f vec3 v_color;"
|
||||
"\n v2f vec3 v_normal;"
|
||||
"\n v2f vec3 v_light;"
|
||||
"\n v2f vec2 v_uv;"
|
||||
"\n "
|
||||
"\n #ifdef VERTEX"
|
||||
"\n "
|
||||
"\n layout(location = 0) in vec3 position;"
|
||||
"\n layout(location = 1) in vec3 normal;"
|
||||
"\n layout(location = 2) in vec3 color;"
|
||||
"\n layout(location = 3) in vec2 uv;"
|
||||
"\n "
|
||||
"\n void main()"
|
||||
"\n {"
|
||||
"\n v_color = color;"
|
||||
"\n v_normal = normal;"
|
||||
"\n v_light = transpose( mat3( view )) * normalize( vec3( 1 ));"
|
||||
"\n v_uv = uv;"
|
||||
"\n "
|
||||
"\n gl_Position = projection * view * vec4( position, 1. );"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
"\n #ifdef FRAGMENT"
|
||||
"\n "
|
||||
"\n out vec4 color;"
|
||||
"\n "
|
||||
"\n void main() "
|
||||
"\n {"
|
||||
"\n float light = .5 + .5 * clamp( dot( v_normal, v_light ), 0., 1. );"
|
||||
"\n vec4 texColor = texture2D( marioTex, v_uv );"
|
||||
"\n vec3 mainColor = mix( v_color, texColor.rgb, texColor.a ); // v_uv.x >= 0. ? texColor.a : 0. );"
|
||||
"\n color = vec4( mainColor * light, 1 );"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
;
|
||||
static const char *WORLD_SHADER =
|
||||
"\n uniform mat4 model;"
|
||||
"\n uniform mat4 view;"
|
||||
"\n uniform mat4 projection;"
|
||||
"\n uniform sampler2D tex;"
|
||||
"\n "
|
||||
"\n v2f vec3 v_normal;"
|
||||
"\n v2f vec3 v_worldPos;"
|
||||
"\n "
|
||||
"\n #ifdef VERTEX"
|
||||
"\n "
|
||||
"\n layout(location = 0) in vec3 position;"
|
||||
"\n layout(location = 1) in vec3 normal;"
|
||||
"\n "
|
||||
"\n void main()"
|
||||
"\n {"
|
||||
"\n v_normal = inverse(mat3(model)) * normal;"
|
||||
"\n vec4 worldPos4 = model * vec4(position, 1.);"
|
||||
"\n v_worldPos = worldPos4.xyz;"
|
||||
"\n gl_Position = projection * view * worldPos4;"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
"\n #ifdef FRAGMENT"
|
||||
"\n "
|
||||
"\n vec3 tri( vec3 x )"
|
||||
"\n {"
|
||||
"\n return abs(x-floor(x)-.5);"
|
||||
"\n } "
|
||||
"\n float surfFunc( vec3 p )"
|
||||
"\n {"
|
||||
"\n float n = dot(tri(p*.15 + tri(p.yzx*.075)), vec3(.444));"
|
||||
"\n p = p*1.5773 - n;"
|
||||
"\n p.yz = vec2(p.y + p.z, p.z - p.y) * .866;"
|
||||
"\n p.xz = vec2(p.x + p.z, p.z - p.x) * .866;"
|
||||
"\n n += dot(tri(p*.225 + tri(p.yzx*.1125)), vec3(.222)); "
|
||||
"\n return abs(n-.5)*1.9 + (1.-abs(sin(n*9.)))*.05;"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n const vec3 light_x = vec3(-1.0, 0.4, 0.9);"
|
||||
"\n "
|
||||
"\n out vec4 color;"
|
||||
"\n "
|
||||
"\n void main() "
|
||||
"\n {"
|
||||
"\n float surfy = surfFunc( v_worldPos / 50. );"
|
||||
"\n float brightness = smoothstep( .2, .3, surfy );"
|
||||
"\n "
|
||||
"\n color = vec4( (0.5 + 0.25 * brightness) * (.5+.5*v_normal), 1 );"
|
||||
"\n }"
|
||||
"\n "
|
||||
"\n #endif"
|
||||
;
|
||||
|
||||
uint8_t *utils_read_file_alloc( const char *path, size_t *fileLength )
|
||||
{
|
||||
FILE *f = fopen( path, "rb" );
|
||||
|
||||
if( !f ) return NULL;
|
||||
|
||||
fseek( f, 0, SEEK_END );
|
||||
size_t length = (size_t)ftell( f );
|
||||
rewind( f );
|
||||
uint8_t *buffer = malloc( length + 1 );
|
||||
fread( buffer, 1, length, f );
|
||||
buffer[length] = 0;
|
||||
fclose( f );
|
||||
|
||||
if( fileLength ) *fileLength = length;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static GLuint shader_compile( const char *shaderContents, size_t shaderContentsLength, GLenum shaderType )
|
||||
{
|
||||
const GLchar *shaderDefine = shaderType == GL_VERTEX_SHADER
|
||||
? "\n#version 410\n#define VERTEX \n#define v2f out\n"
|
||||
: "\n#version 410\n#define FRAGMENT\n#define v2f in \n";
|
||||
|
||||
const GLchar *shaderStrings[2] = { shaderDefine, shaderContents };
|
||||
GLint shaderStringLengths[2] = { strlen( shaderDefine ), (GLint)shaderContentsLength };
|
||||
|
||||
GLuint shader = glCreateShader( shaderType );
|
||||
glShaderSource( shader, 2, shaderStrings, shaderStringLengths );
|
||||
glCompileShader( shader );
|
||||
|
||||
GLint isCompiled;
|
||||
glGetShaderiv( shader, GL_COMPILE_STATUS, &isCompiled );
|
||||
if( isCompiled == GL_FALSE )
|
||||
{
|
||||
GLint maxLength;
|
||||
glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &maxLength );
|
||||
char *log = (char*)malloc( maxLength );
|
||||
glGetShaderInfoLog( shader, maxLength, &maxLength, log );
|
||||
|
||||
printf( "Error in shader: %s\n%s\n%s\n", log, shaderStrings[0], shaderStrings[1] );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
static GLuint shader_load( const char *shaderContents )
|
||||
{
|
||||
GLuint result;
|
||||
GLuint vert = shader_compile( shaderContents, strlen( shaderContents ), GL_VERTEX_SHADER );
|
||||
GLuint frag = shader_compile( shaderContents, strlen( shaderContents ), GL_FRAGMENT_SHADER );
|
||||
|
||||
GLuint ref = glCreateProgram();
|
||||
glAttachShader( ref, vert );
|
||||
glAttachShader( ref, frag );
|
||||
glLinkProgram ( ref );
|
||||
glDetachShader( ref, vert );
|
||||
glDetachShader( ref, frag );
|
||||
result = ref;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void load_collision_mesh( CollisionMesh *mesh )
|
||||
{
|
||||
mesh->num_vertices = 3 * surfaces_count;
|
||||
mesh->position = malloc( sizeof( float ) * surfaces_count * 9 );
|
||||
mesh->normal = malloc( sizeof( float ) * surfaces_count * 9 );
|
||||
mesh->index = malloc( sizeof( uint16_t ) * surfaces_count * 3 );
|
||||
|
||||
for( size_t i = 0; i < surfaces_count; ++i )
|
||||
{
|
||||
const struct SM64Surface *surf = &surfaces[i];
|
||||
|
||||
float x1 = mesh->position[9*i+0] = surf->vertices[0][0];
|
||||
float y1 = mesh->position[9*i+1] = surf->vertices[0][1];
|
||||
float z1 = mesh->position[9*i+2] = surf->vertices[0][2];
|
||||
float x2 = mesh->position[9*i+3] = surf->vertices[1][0];
|
||||
float y2 = mesh->position[9*i+4] = surf->vertices[1][1];
|
||||
float z2 = mesh->position[9*i+5] = surf->vertices[1][2];
|
||||
float x3 = mesh->position[9*i+6] = surf->vertices[2][0];
|
||||
float y3 = mesh->position[9*i+7] = surf->vertices[2][1];
|
||||
float z3 = mesh->position[9*i+8] = surf->vertices[2][2];
|
||||
|
||||
float nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2);
|
||||
float ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2);
|
||||
float nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
|
||||
float mag = sqrtf(nx * nx + ny * ny + nz * nz);
|
||||
nx /= mag;
|
||||
ny /= mag;
|
||||
nz /= mag;
|
||||
|
||||
mesh->normal[9*i+0] = nx;
|
||||
mesh->normal[9*i+1] = ny;
|
||||
mesh->normal[9*i+2] = nz;
|
||||
mesh->normal[9*i+3] = nx;
|
||||
mesh->normal[9*i+4] = ny;
|
||||
mesh->normal[9*i+5] = nz;
|
||||
mesh->normal[9*i+6] = nx;
|
||||
mesh->normal[9*i+7] = ny;
|
||||
mesh->normal[9*i+8] = nz;
|
||||
|
||||
mesh->index[3*i+0] = 3*i+0;
|
||||
mesh->index[3*i+1] = 3*i+1;
|
||||
mesh->index[3*i+2] = 3*i+2;
|
||||
}
|
||||
|
||||
glGenVertexArrays( 1, &mesh->vao );
|
||||
glBindVertexArray( mesh->vao );
|
||||
|
||||
#define X( loc, buff, arr, type ) do { \
|
||||
glGenBuffers( 1, &buff ); \
|
||||
glBindBuffer( GL_ARRAY_BUFFER, buff ); \
|
||||
glBufferData( GL_ARRAY_BUFFER, mesh->num_vertices*sizeof( type ), arr, GL_STATIC_DRAW ); \
|
||||
glEnableVertexAttribArray( loc ); \
|
||||
glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \
|
||||
} while( 0 )
|
||||
|
||||
X( 0, mesh->position_buffer, mesh->position, vec3 );
|
||||
X( 1, mesh->normal_buffer, mesh->normal, vec3 );
|
||||
|
||||
#undef X
|
||||
}
|
||||
|
||||
static void load_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo )
|
||||
{
|
||||
mesh->index = malloc( 3 * SM64_GEO_MAX_TRIANGLES * sizeof(uint16_t) );
|
||||
for( int i = 0; i < 3 * SM64_GEO_MAX_TRIANGLES; ++i )
|
||||
mesh->index[i] = i;
|
||||
|
||||
mesh->num_vertices = 3 * SM64_GEO_MAX_TRIANGLES;
|
||||
|
||||
glGenVertexArrays( 1, &mesh->vao );
|
||||
glBindVertexArray( mesh->vao );
|
||||
|
||||
#define X( loc, buff, arr, type ) do { \
|
||||
glGenBuffers( 1, &buff ); \
|
||||
glBindBuffer( GL_ARRAY_BUFFER, buff ); \
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( type ) * 3 * SM64_GEO_MAX_TRIANGLES, arr, GL_DYNAMIC_DRAW ); \
|
||||
glEnableVertexAttribArray( loc ); \
|
||||
glVertexAttribPointer( loc, sizeof( type ) / sizeof( float ), GL_FLOAT, GL_FALSE, sizeof( type ), NULL ); \
|
||||
} while( 0 )
|
||||
|
||||
X( 0, mesh->position_buffer, marioGeo->position, vec3 );
|
||||
X( 1, mesh->normal_buffer, marioGeo->normal, vec3 );
|
||||
X( 2, mesh->color_buffer, marioGeo->color, vec3 );
|
||||
X( 3, mesh->uv_buffer, marioGeo->uv, vec2 );
|
||||
|
||||
#undef X
|
||||
}
|
||||
|
||||
static void update_mario_mesh( MarioMesh *mesh, struct SM64MarioGeometryBuffers *marioGeo )
|
||||
{
|
||||
if( mesh->index == NULL )
|
||||
load_mario_mesh( mesh, marioGeo );
|
||||
|
||||
mesh->num_vertices = 3 * marioGeo->numTrianglesUsed;
|
||||
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->position_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->position, GL_DYNAMIC_DRAW );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->normal_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->normal, GL_DYNAMIC_DRAW );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->color_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec3 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->color, GL_DYNAMIC_DRAW );
|
||||
glBindBuffer( GL_ARRAY_BUFFER, mesh->uv_buffer );
|
||||
glBufferData( GL_ARRAY_BUFFER, sizeof( vec2 ) * 3 * SM64_GEO_MAX_TRIANGLES, marioGeo->uv, GL_DYNAMIC_DRAW );
|
||||
}
|
||||
|
||||
void render_state_init( RenderState *renderState, uint8_t *marioTexture )
|
||||
{
|
||||
load_collision_mesh( &renderState->collision );
|
||||
renderState->world_shader = shader_load( WORLD_SHADER );
|
||||
renderState->mario_shader = shader_load( MARIO_SHADER );
|
||||
|
||||
glEnable( GL_CULL_FACE );
|
||||
glCullFace( GL_BACK );
|
||||
glClearColor( 0.2f, 0.2f, 0.2f, 1.0f );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
|
||||
glGenTextures( 1, &renderState->mario_texture );
|
||||
glBindTexture( GL_TEXTURE_2D, renderState->mario_texture );
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, SM64_TEXTURE_WIDTH, SM64_TEXTURE_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, marioTexture);
|
||||
}
|
||||
|
||||
void render_draw( RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo )
|
||||
{
|
||||
update_mario_mesh( &renderState->mario, marioGeo );
|
||||
|
||||
mat4 model, view, projection;
|
||||
glm_perspective( 45.0f, (float)WINDOW_WIDTH / (float)WINDOW_HEIGHT, 100.0f, 20000.0f, projection );
|
||||
glm_translate( view, (float*)camPos );
|
||||
glm_lookat( (float*)camPos, (float*)marioState->position, (vec3){0,1,0}, view );
|
||||
glm_mat4_identity( model );
|
||||
|
||||
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
||||
|
||||
glUseProgram( renderState->world_shader );
|
||||
glBindVertexArray( renderState->collision.vao );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "model" ), 1, GL_FALSE, (GLfloat*)model );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "view" ), 1, GL_FALSE, (GLfloat*)view );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->world_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection );
|
||||
glDrawElements( GL_TRIANGLES, renderState->collision.num_vertices, GL_UNSIGNED_SHORT, renderState->collision.index );
|
||||
|
||||
glUseProgram( renderState->mario_shader );
|
||||
glActiveTexture( GL_TEXTURE0 );
|
||||
glBindTexture( GL_TEXTURE_2D, renderState->mario_texture );
|
||||
glBindVertexArray( renderState->mario.vao );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "view" ), 1, GL_FALSE, (GLfloat*)view );
|
||||
glUniformMatrix4fv( glGetUniformLocation( renderState->mario_shader, "projection" ), 1, GL_FALSE, (GLfloat*)projection );
|
||||
glUniform1i( glGetUniformLocation( renderState->mario_shader, "marioTex" ), 0 );
|
||||
glDrawElements( GL_TRIANGLES, renderState->mario.num_vertices, GL_UNSIGNED_SHORT, renderState->mario.index );
|
||||
}
|
||||
|
||||
static float read_axis( int16_t val )
|
||||
{
|
||||
float result = (float)val / 32767.0f;
|
||||
|
||||
if( result < 0.2f && result > -0.2f )
|
||||
return 0.0f;
|
||||
|
||||
return result > 0.0f ? (result - 0.2f) / 0.8f : (result + 0.2f) / 0.8f;
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
size_t romSize;
|
||||
|
||||
uint8_t *rom = utils_read_file_alloc( "baserom.us.z64", &romSize );
|
||||
|
||||
if( rom == NULL )
|
||||
{
|
||||
printf("\nFailed to read ROM file \"baserom.us.z64\"\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *texture = malloc( 4 * SM64_TEXTURE_WIDTH * SM64_TEXTURE_HEIGHT );
|
||||
|
||||
sm64_global_terminate();
|
||||
sm64_global_init( rom, texture );
|
||||
sm64_static_surfaces_load( surfaces, surfaces_count );
|
||||
uint32_t marioId = sm64_mario_create( 0, 1000, 0 );
|
||||
|
||||
free( rom );
|
||||
|
||||
RenderState renderState;
|
||||
renderState.mario.index = NULL;
|
||||
vec3 cameraPos = { 0, 0, 0 };
|
||||
float cameraRot = 0.0f;
|
||||
|
||||
context_init( "libsm64", WINDOW_WIDTH, WINDOW_HEIGHT );
|
||||
render_state_init( &renderState, texture );
|
||||
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
|
||||
struct SM64MarioInputs marioInputs;
|
||||
struct SM64MarioState marioState;
|
||||
struct SM64MarioGeometryBuffers marioGeometry;
|
||||
|
||||
marioGeometry.position = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES );
|
||||
marioGeometry.color = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES );
|
||||
marioGeometry.normal = malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES );
|
||||
marioGeometry.uv = malloc( sizeof(float) * 6 * SM64_GEO_MAX_TRIANGLES );
|
||||
|
||||
do
|
||||
{
|
||||
uint64_t frameTopTime = ns_clock();
|
||||
|
||||
SDL_GameController *controller = context_get_controller();
|
||||
float x_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTX ));
|
||||
float y_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTY ));
|
||||
float x0_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_RIGHTX ));
|
||||
|
||||
cameraRot += 0.1f * x0_axis;
|
||||
cameraPos[0] = marioState.position[0] + 1000.0f * cosf( cameraRot );
|
||||
cameraPos[1] = marioState.position[1] + 200.0f;
|
||||
cameraPos[2] = marioState.position[2] + 1000.0f * sinf( cameraRot );
|
||||
|
||||
marioInputs.buttonA = SDL_GameControllerGetButton( controller, 0 );
|
||||
marioInputs.buttonB = SDL_GameControllerGetButton( controller, 2 );
|
||||
marioInputs.buttonZ = SDL_GameControllerGetButton( controller, 9 );
|
||||
marioInputs.camLookX = marioState.position[0] - cameraPos[0];
|
||||
marioInputs.camLookZ = marioState.position[2] - cameraPos[2];
|
||||
marioInputs.stickX = x_axis;
|
||||
marioInputs.stickY = y_axis;
|
||||
|
||||
sm64_mario_tick( marioId, &marioInputs, &marioState, &marioGeometry );
|
||||
|
||||
render_draw( &renderState, cameraPos, &marioState, &marioGeometry );
|
||||
|
||||
ts.tv_nsec = 33333333 - (ns_clock() - frameTopTime);
|
||||
nanosleep( &ts, &ts );
|
||||
}
|
||||
while( context_flip_frame_poll_events() );
|
||||
|
||||
sm64_global_terminate();
|
||||
context_terminate();
|
||||
|
||||
return 0;
|
||||
}
|
226
test/main.cpp
Normal file
226
test/main.cpp
Normal file
|
@ -0,0 +1,226 @@
|
|||
#define _CRT_SECURE_NO_WARNINGS 1 // for fopen
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
extern "C" {
|
||||
#include "../src/libsm64.h"
|
||||
#define SDL_MAIN_HANDLED
|
||||
#include "level.h"
|
||||
#include "context.h"
|
||||
#include "renderer.h"
|
||||
#include "gl33core/gl33core_renderer.h"
|
||||
#include "gl20/gl20_renderer.h"
|
||||
}
|
||||
|
||||
#include "audio.h"
|
||||
|
||||
uint8_t *utils_read_file_alloc( const char *path, size_t *fileLength )
|
||||
{
|
||||
FILE *f = fopen( path, "rb" );
|
||||
|
||||
if( !f ) return NULL;
|
||||
|
||||
fseek( f, 0, SEEK_END );
|
||||
size_t length = (size_t)ftell( f );
|
||||
rewind( f );
|
||||
uint8_t *buffer = (uint8_t*)malloc( length + 1 );
|
||||
fread( buffer, 1, length, f );
|
||||
buffer[length] = 0;
|
||||
fclose( f );
|
||||
|
||||
if( fileLength ) *fileLength = length;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static float read_axis( int16_t val )
|
||||
{
|
||||
float result = (float)val / 32767.0f;
|
||||
|
||||
if( result < 0.2f && result > -0.2f )
|
||||
return 0.0f;
|
||||
|
||||
return result > 0.0f ? (result - 0.2f) / 0.8f : (result + 0.2f) / 0.8f;
|
||||
}
|
||||
|
||||
float lerp(float a, float b, float amount)
|
||||
{
|
||||
return a + (b - a) * amount;
|
||||
}
|
||||
|
||||
int main( void )
|
||||
{
|
||||
size_t romSize;
|
||||
|
||||
uint8_t *rom = utils_read_file_alloc( "baserom.us.z64", &romSize );
|
||||
|
||||
if( rom == NULL )
|
||||
{
|
||||
printf("\nFailed to read ROM file \"baserom.us.z64\"\n\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *texture = (uint8_t*)malloc( 4 * SM64_TEXTURE_WIDTH * SM64_TEXTURE_HEIGHT );
|
||||
|
||||
sm64_global_terminate();
|
||||
sm64_global_init( rom, texture );
|
||||
sm64_audio_init(rom);
|
||||
sm64_static_surfaces_load( surfaces, surfaces_count );
|
||||
uint32_t marioId = sm64_mario_create( 0, 1000, 0 );
|
||||
|
||||
free( rom );
|
||||
|
||||
RenderState renderState;
|
||||
renderState.mario.index = NULL;
|
||||
vec3 cameraPos = { 0, 0, 0 };
|
||||
float cameraRot = 0.0f;
|
||||
|
||||
struct Renderer *renderer;
|
||||
|
||||
int major, minor;
|
||||
#ifdef GL33_CORE
|
||||
major = 3; minor = 3;
|
||||
renderer = &gl33core_renderer;
|
||||
#else
|
||||
major = 2; minor = 0;
|
||||
renderer = &gl20_renderer;
|
||||
#endif
|
||||
|
||||
context_init( "libsm64", 800, 600, major, minor );
|
||||
renderer->init( &renderState, texture );
|
||||
|
||||
struct SM64MarioInputs marioInputs;
|
||||
struct SM64MarioState marioState;
|
||||
struct SM64MarioGeometryBuffers marioGeometry;
|
||||
|
||||
// interpolation
|
||||
float lastPos[3], currPos[3];
|
||||
float lastGeoPos[9 * SM64_GEO_MAX_TRIANGLES], currGeoPos[9 * SM64_GEO_MAX_TRIANGLES];
|
||||
|
||||
marioGeometry.position = (float*)malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES );
|
||||
marioGeometry.color = (float*)malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES );
|
||||
marioGeometry.normal = (float*)malloc( sizeof(float) * 9 * SM64_GEO_MAX_TRIANGLES );
|
||||
marioGeometry.uv = (float*)malloc( sizeof(float) * 6 * SM64_GEO_MAX_TRIANGLES );
|
||||
marioGeometry.numTrianglesUsed = 0;
|
||||
|
||||
float tick = 0;
|
||||
uint32_t lastTicks = SDL_GetTicks();
|
||||
|
||||
audio_init();
|
||||
|
||||
do
|
||||
{
|
||||
float dt = (SDL_GetTicks() - lastTicks) / 1000.f;
|
||||
lastTicks = SDL_GetTicks();
|
||||
tick += dt;
|
||||
|
||||
SDL_GameController *controller = context_get_controller();
|
||||
float x_axis, y_axis, x0_axis;
|
||||
|
||||
if (!controller) // keyboard
|
||||
{
|
||||
const Uint8* state = SDL_GetKeyboardState(NULL);
|
||||
|
||||
float dir;
|
||||
float spd = 0;
|
||||
if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_RIGHT])
|
||||
{
|
||||
dir = -M_PI * 0.25f;
|
||||
spd = 1;
|
||||
}
|
||||
else if (state[SDL_SCANCODE_UP] && state[SDL_SCANCODE_LEFT])
|
||||
{
|
||||
dir = -M_PI * 0.75f;
|
||||
spd = 1;
|
||||
}
|
||||
else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_RIGHT])
|
||||
{
|
||||
dir = M_PI * 0.25f;
|
||||
spd = 1;
|
||||
}
|
||||
else if (state[SDL_SCANCODE_DOWN] && state[SDL_SCANCODE_LEFT])
|
||||
{
|
||||
dir = M_PI * 0.75f;
|
||||
spd = 1;
|
||||
}
|
||||
else if (state[SDL_SCANCODE_UP])
|
||||
{
|
||||
dir = -M_PI * 0.5f;
|
||||
spd = 1;
|
||||
}
|
||||
else if (state[SDL_SCANCODE_DOWN])
|
||||
{
|
||||
dir = M_PI * 0.5f;
|
||||
spd = 1;
|
||||
}
|
||||
else if (state[SDL_SCANCODE_LEFT])
|
||||
{
|
||||
dir = M_PI;
|
||||
spd = 1;
|
||||
}
|
||||
else if (state[SDL_SCANCODE_RIGHT])
|
||||
{
|
||||
dir = 0;
|
||||
spd = 1;
|
||||
}
|
||||
|
||||
x_axis = cosf(dir) * spd;
|
||||
y_axis = sinf(dir) * spd;
|
||||
x0_axis = state[SDL_SCANCODE_LSHIFT] ? 1 : state[SDL_SCANCODE_RSHIFT] ? -1 : 0;
|
||||
|
||||
marioInputs.buttonA = state[SDL_SCANCODE_X];
|
||||
marioInputs.buttonB = state[SDL_SCANCODE_C];
|
||||
marioInputs.buttonZ = state[SDL_SCANCODE_Z];
|
||||
}
|
||||
else
|
||||
{
|
||||
x_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTX ));
|
||||
y_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_LEFTY ));
|
||||
x0_axis = read_axis( SDL_GameControllerGetAxis( controller, SDL_CONTROLLER_AXIS_RIGHTX ));
|
||||
|
||||
marioInputs.buttonA = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_A );
|
||||
marioInputs.buttonB = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_X );
|
||||
marioInputs.buttonZ = SDL_GameControllerGetButton( controller, SDL_CONTROLLER_BUTTON_LEFTSHOULDER );
|
||||
}
|
||||
|
||||
cameraRot += x0_axis * dt * 2;
|
||||
cameraPos[0] = marioState.position[0] + 1000.0f * cosf( cameraRot );
|
||||
cameraPos[1] = marioState.position[1] + 200.0f;
|
||||
cameraPos[2] = marioState.position[2] + 1000.0f * sinf( cameraRot );
|
||||
|
||||
marioInputs.camLookX = marioState.position[0] - cameraPos[0];
|
||||
marioInputs.camLookZ = marioState.position[2] - cameraPos[2];
|
||||
marioInputs.stickX = x_axis;
|
||||
marioInputs.stickY = y_axis;
|
||||
|
||||
while (tick >= 1.f/30)
|
||||
{
|
||||
memcpy(lastPos, currPos, sizeof(currPos));
|
||||
memcpy(lastGeoPos, currGeoPos, sizeof(currGeoPos));
|
||||
|
||||
tick -= 1.f/30;
|
||||
sm64_mario_tick( marioId, &marioInputs, &marioState, &marioGeometry );
|
||||
|
||||
memcpy(currPos, marioState.position, sizeof(currPos));
|
||||
memcpy(currGeoPos, marioGeometry.position, sizeof(currGeoPos));
|
||||
}
|
||||
|
||||
for (int i=0; i<3; i++) marioState.position[i] = lerp(lastPos[i], currPos[i], tick / (1.f/30));
|
||||
for (int i=0; i<marioGeometry.numTrianglesUsed*9; i++) marioGeometry.position[i] = lerp(lastGeoPos[i], currGeoPos[i], tick / (1.f/30));
|
||||
|
||||
renderer->draw( &renderState, cameraPos, &marioState, &marioGeometry );
|
||||
}
|
||||
while( context_flip_frame_poll_events() );
|
||||
|
||||
sm64_global_terminate();
|
||||
context_terminate();
|
||||
|
||||
return 0;
|
||||
}
|
65
test/renderer.h
Normal file
65
test/renderer.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef RENDERER_H
|
||||
#define RENDERER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "../src/libsm64.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "context.h"
|
||||
#include "cglm.h"
|
||||
|
||||
typedef struct CollisionMesh
|
||||
{
|
||||
size_t num_vertices;
|
||||
float *position;
|
||||
float *normal;
|
||||
float *color;
|
||||
uint16_t *index;
|
||||
|
||||
GLuint vao;
|
||||
GLuint position_buffer;
|
||||
GLuint normal_buffer;
|
||||
}
|
||||
CollisionMesh;
|
||||
|
||||
typedef struct MarioMesh
|
||||
{
|
||||
size_t num_vertices;
|
||||
uint16_t *index;
|
||||
|
||||
GLuint vao;
|
||||
GLuint position_buffer;
|
||||
GLuint normal_buffer;
|
||||
GLuint color_buffer;
|
||||
GLuint uv_buffer;
|
||||
}
|
||||
MarioMesh;
|
||||
|
||||
typedef struct RenderState
|
||||
{
|
||||
CollisionMesh collision;
|
||||
MarioMesh mario;
|
||||
GLuint world_shader;
|
||||
GLuint mario_shader;
|
||||
GLuint mario_texture;
|
||||
}
|
||||
RenderState;
|
||||
|
||||
|
||||
struct Renderer
|
||||
{
|
||||
void (*init)(RenderState *renderState, uint8_t *marioTexture);
|
||||
void (*draw)(RenderState *renderState, const vec3 camPos, const struct SM64MarioState *marioState, struct SM64MarioGeometryBuffers *marioGeo);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue