Add a new sample to the opengl folder, to load 3D models

This commit is contained in:
Niko 2019-02-10 14:05:30 -05:00
parent 038845fd20
commit 500bb72334
11 changed files with 93342 additions and 0 deletions

View File

@ -0,0 +1,213 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITPRO)),)
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
endif
TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# EXEFS_SRC is the optional input directory containing data copied into exefs, if anything this normally should only contain "main.npdm".
# ROMFS is the directory containing data to be added to RomFS, relative to the Makefile (Optional)
#
# NO_ICON: if set to anything, do not use icon.
# NO_NACP: if set to anything, no .nacp file is generated.
# APP_TITLE is the name of the app stored in the .nacp file (Optional)
# APP_AUTHOR is the author of the app stored in the .nacp file (Optional)
# APP_VERSION is the version of the app stored in the .nacp file (Optional)
# APP_TITLEID is the titleID of the app stored in the .nacp file (Optional)
# ICON is the filename of the icon (.jpg), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.jpg
# - icon.jpg
# - <libnx folder>/default_icon.jpg
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := source
DATA := data
INCLUDES := include
EXEFS_SRC := exefs_src
ROMFS := romfs
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CFLAGS += $(INCLUDE) -D__SWITCH__
# The following line works around an issue in newlib that produces a compilation
# error in glm. It will be removed as soon as this issue is resolved.
CFLAGS += -D_GLIBCXX_USE_C99_MATH_TR1 -D_LDBL_EQ_DBL
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := -lglad -lEGL -lglapi -ldrm_nouveau -lnx -lm
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(PORTLIBS) $(LIBNX)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
export BUILD_EXEFS_SRC := $(TOPDIR)/$(EXEFS_SRC)
ifeq ($(strip $(ICON)),)
icons := $(wildcard *.jpg)
ifneq (,$(findstring $(TARGET).jpg,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).jpg
else
ifneq (,$(findstring icon.jpg,$(icons)))
export APP_ICON := $(TOPDIR)/icon.jpg
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif
ifeq ($(strip $(NO_ICON)),)
export NROFLAGS += --icon=$(APP_ICON)
endif
ifeq ($(strip $(NO_NACP)),)
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
endif
ifneq ($(APP_TITLEID),)
export NACPFLAGS += --titleid=$(APP_TITLEID)
endif
ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
/d/Games/2017_Switch/canary/yuzu-cmd.exe $(TARGET).nro
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).pfs0 $(TARGET).nso $(TARGET).nro $(TARGET).nacp $(TARGET).elf
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).pfs0 $(OUTPUT).nro
$(OUTPUT).pfs0 : $(OUTPUT).nso
$(OUTPUT).nso : $(OUTPUT).elf
ifeq ($(strip $(NO_NACP)),)
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp
else
$(OUTPUT).nro : $(OUTPUT).elf
endif
$(OUTPUT).elf : $(OFILES)
$(OFILES_SRC) : $(HFILES_BIN)
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o %_bin.h : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.png.o %_png.h : %.png
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
#---------------------------------------------------------------------------------
%.3Dobj.o %_3Dobj.h : %.3Dobj
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@perl $(CURDIR)/../Obj2Bin.pl $(CURDIR)/../data/$(notdir $<) -o $(CURDIR)/$(basename $(notdir $<) )
@$(CXX) $(CXXFLAGS) -c $(CURDIR)/$(basename $(notdir $<) ).3Dobj.cpp -o $(CURDIR)/$(basename $(notdir $<) ).3Dobj.o $(ERROR_FILTER)
@rm -f $(CURDIR)/$(basename $(notdir $<) ).3Dobj.cpp
@mv $(CURDIR)/$(basename $(notdir $<) ).3Dobj.h $(CURDIR)/$(basename $(notdir $<) )_3Dobj.h
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 999 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 KiB

View File

@ -0,0 +1,50 @@
# Blender v2.79 (sub 0) OBJ File: ''
# www.blender.org
o Cube
v 0.330000 -0.330000 -0.330000
v 0.330000 -0.330000 0.330000
v -0.330000 -0.330000 0.330000
v -0.330000 -0.330000 -0.330000
v 0.330000 0.330000 -0.330000
v 0.330000 0.330000 0.330000
v -0.330000 0.330000 0.330000
v -0.330000 0.330000 -0.330000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 0.000000 0.000000
vt 0.000000 0.000000
vt 1.000000 1.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vt 1.000000 1.000000
vt 1.000000 1.000000
vt 1.000000 0.000000
vt 1.000000 1.000000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 1.0000 -0.0000 0.0000
vn -0.0000 -0.0000 1.0000
vn -1.0000 -0.0000 -0.0000
vn 0.0000 0.0000 -1.0000
s off
f 2/1/1 4/2/1 1/3/1
f 8/4/2 6/5/2 5/6/2
f 5/7/3 2/8/3 1/3/3
f 6/9/4 3/10/4 2/11/4
f 3/12/5 8/13/5 4/2/5
f 1/14/6 8/15/6 5/6/6
f 2/1/1 3/16/1 4/2/1
f 8/4/2 7/17/2 6/5/2
f 5/7/3 6/18/3 2/8/3
f 6/9/4 7/17/4 3/10/4
f 3/12/5 7/19/5 8/13/5
f 1/14/6 4/20/6 8/15/6

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,685 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <switch.h>
#include <vector>
#include <EGL/egl.h> // EGL library
#include <EGL/eglext.h> // EGL extensions
#include <glad/glad.h> // glad library (OpenGL loader)
// GLM headers
#define GLM_FORCE_PURE
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "stb_image.h"
constexpr auto TAU = glm::two_pi<float>();
//-----------------------------------------------------------------------------
// nxlink support
//-----------------------------------------------------------------------------
#ifndef ENABLE_NXLINK
#define TRACE(fmt,...) ((void)0)
#else
#include <unistd.h>
#define TRACE(fmt,...) printf("%s: " fmt "\n", __PRETTY_FUNCTION__, ## __VA_ARGS__)
static int s_nxlinkSock = -1;
static void initNxLink()
{
if (R_FAILED(socketInitializeDefault()))
return;
s_nxlinkSock = nxlinkStdio();
if (s_nxlinkSock >= 0)
TRACE("printf output now goes to nxlink server");
else
socketExit();
}
static void deinitNxLink()
{
if (s_nxlinkSock >= 0)
{
close(s_nxlinkSock);
socketExit();
s_nxlinkSock = -1;
}
}
extern "C" void userAppInit()
{
initNxLink();
}
extern "C" void userAppExit()
{
deinitNxLink();
}
#endif
//-----------------------------------------------------------------------------
// EGL initialization
//-----------------------------------------------------------------------------
static EGLDisplay s_display;
static EGLContext s_context;
static EGLSurface s_surface;
static bool initEgl(NWindow* win)
{
// Connect to the EGL default display
s_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (!s_display)
{
TRACE("Could not connect to display! error: %d", eglGetError());
goto _fail0;
}
// Initialize the EGL display connection
eglInitialize(s_display, nullptr, nullptr);
// Select OpenGL (Core) as the desired graphics API
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE)
{
TRACE("Could not set API! error: %d", eglGetError());
goto _fail1;
}
// Get an appropriate EGL framebuffer configuration
EGLConfig config;
EGLint numConfigs;
static const EGLint framebufferAttributeList[] =
{
EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};
eglChooseConfig(s_display, framebufferAttributeList, &config, 1, &numConfigs);
if (numConfigs == 0)
{
TRACE("No config found! error: %d", eglGetError());
goto _fail1;
}
// Create an EGL window surface
s_surface = eglCreateWindowSurface(s_display, config, win, nullptr);
if (!s_surface)
{
TRACE("Surface creation failed! error: %d", eglGetError());
goto _fail1;
}
// Create an EGL rendering context
static const EGLint contextAttributeList[] =
{
EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
EGL_CONTEXT_MAJOR_VERSION_KHR, 4,
EGL_CONTEXT_MINOR_VERSION_KHR, 3,
EGL_NONE
};
s_context = eglCreateContext(s_display, config, EGL_NO_CONTEXT, contextAttributeList);
if (!s_context)
{
TRACE("Context creation failed! error: %d", eglGetError());
goto _fail2;
}
// Connect the context to the surface
eglMakeCurrent(s_display, s_surface, s_surface, s_context);
return true;
_fail2:
eglDestroySurface(s_display, s_surface);
s_surface = nullptr;
_fail1:
eglTerminate(s_display);
s_display = nullptr;
_fail0:
return false;
}
static void deinitEgl()
{
if (s_display)
{
eglMakeCurrent(s_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
if (s_context)
{
eglDestroyContext(s_display, s_context);
s_context = nullptr;
}
if (s_surface)
{
eglDestroySurface(s_display, s_surface);
s_surface = nullptr;
}
eglTerminate(s_display);
s_display = nullptr;
}
}
//-----------------------------------------------------------------------------
// Main program
//-----------------------------------------------------------------------------
static void setMesaConfig()
{
// Uncomment below to disable error checking and save CPU time (useful for production):
//setenv("MESA_NO_ERROR", "1", 1);
// Uncomment below to enable Mesa logging:
//setenv("EGL_LOG_LEVEL", "debug", 1);
//setenv("MESA_VERBOSE", "all", 1);
//setenv("NOUVEAU_MESA_DEBUG", "1", 1);
// Uncomment below to enable shader debugging in Nouveau:
//setenv("NV50_PROG_OPTIMIZE", "0", 1);
//setenv("NV50_PROG_DEBUG", "1", 1);
//setenv("NV50_PROG_CHIPSET", "0x120", 1);
}
static const char* const vertexShaderSource = R"text(
#version 320 es
precision mediump float;
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inTexCoord;
layout (location = 2) in vec3 inNormal;
out vec2 vtxTexCoord;
out vec4 vtxNormalQuat;
out vec3 vtxView;
uniform mat4 mdlvMtx;
uniform mat4 projMtx;
void main()
{
// Calculate position
vec4 pos = mdlvMtx * vec4(inPos, 1.0);
vtxView = -pos.xyz;
gl_Position = projMtx * pos;
// Calculate normalquat
vec3 normal = normalize(mat3(mdlvMtx) * inNormal);
float z = (1.0 + normal.z) / 2.0;
vtxNormalQuat = vec4(1.0, 0.0, 0.0, 0.0);
if (z > 0.0)
{
vtxNormalQuat.z = sqrt(z);
vtxNormalQuat.xy = normal.xy / (2.0 * vtxNormalQuat.z);
}
// Calculate texcoord
vtxTexCoord = inTexCoord;
}
)text";
static const char* const fragmentShaderSource = R"text(
#version 320 es
precision mediump float;
in vec2 vtxTexCoord;
in vec4 vtxNormalQuat;
in vec3 vtxView;
out vec4 fragColor;
uniform vec4 lightPos;
uniform vec3 lightAmbient;
uniform vec3 lightDiffuse;
uniform vec4 lightSpecular; // w component is shininess
uniform sampler2D tex_diffuse;
uniform sampler2D tex_specular;
uniform sampler2D tex_ambOcc;
uniform sampler2D tex_normal;
uniform sampler2D tex_rough;
mat3 cotangent_frame( vec3 N, vec3 p, vec2 uv )
{
// get edge vectors of the pixel triangle
vec3 dp1 = dFdx( p );
vec3 dp2 = dFdy( p );
vec2 duv1 = dFdx( uv );
vec2 duv2 = dFdy( uv );
// solve the linear system
vec3 dp2perp = cross( dp2, N );
vec3 dp1perp = cross( N, dp1 );
vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;
vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;
// construct a scale-invariant frame
float invmax = inversesqrt( max( dot(T,T), dot(B,B) ) );
return mat3( T * invmax, B * invmax, N );
}
vec3 perturb_normal( vec3 N, vec3 V, vec2 texcoord )
{
vec3 map = texture( tex_normal, texcoord ).xyz;
mat3 TBN = cotangent_frame( N, -V, texcoord );
return normalize( TBN * map );
}
void main()
{
vec4 texDiffuseColor = texture(tex_diffuse, vtxTexCoord);
vec4 texSpecularColor = texture(tex_specular, vtxTexCoord);
vec4 texAmbientColor = texture(tex_ambOcc, vtxTexCoord);
vec4 texRoughColor = texture(tex_rough, vtxTexCoord);
vec3 normal = normalize(vtxNormalQuat.xyz);
vec3 lightVec = normalize(lightPos.xyz + vtxView);
vec3 viewVec = normalize(vtxView);
vec3 halfVec = normalize(viewVec + lightVec);
normal = perturb_normal(normal, lightVec, vtxTexCoord);
float diffuseFactor = max(dot(lightVec, normal), 0.0);
float specularFactor = pow(max(dot(normal, halfVec), 0.0), lightSpecular.w);
vec3 finalAmbient = texAmbientColor.rgb * lightAmbient;
vec3 finalSpecular = texSpecularColor.r * specularFactor* lightSpecular.xyz;
vec3 finalDiffuse = texDiffuseColor.rgb * diffuseFactor * lightDiffuse.xyz;
vec3 fragLightColor = finalAmbient + finalDiffuse + finalSpecular;
fragLightColor *= ( vec3(1) - texRoughColor.xyz );
fragColor = vec4(fragLightColor, 1.0);
}
)text";
static GLuint createAndCompileShader(GLenum type, const char* source)
{
GLint success;
GLchar msg[512];
GLuint handle = glCreateShader(type);
if (!handle)
{
TRACE("%u: cannot create shader", type);
return 0;
}
glShaderSource(handle, 1, &source, nullptr);
glCompileShader(handle);
glGetShaderiv(handle, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE)
{
glGetShaderInfoLog(handle, sizeof(msg), nullptr, msg);
TRACE("%u: %s\n", type, msg);
glDeleteShader(handle);
return 0;
}
return handle;
}
typedef struct
{
float position[3];
float texcoord[2];
float normal[3];
} Vertex;
static GLuint s_program;
static GLuint s_vao, s_vbo;
static GLint loc_mdlvMtx, loc_projMtx;
static GLint loc_lightPos, loc_ambient, loc_diffuse, loc_specular;
static GLuint s_tex_diffuse, s_tex_specular, s_tex_ambOcc, s_tex_normal, s_tex_rough;
static GLint loc_tex_diffuse, loc_tex_specular, loc_tex_ambOcc, loc_tex_normal, loc_tex_rough;
static u64 s_startTicks;
void readPNG(const char* path, char** data, int* size)
{
FILE *fp = fopen ( path , "rb" );
fseek( fp , 0L , SEEK_END);
*size = ftell( fp );
rewind( fp );
*data = (char*)calloc( 1, *size+1 );
fread( *data , *size, 1 , fp);
fclose(fp);
}
Vertex* gunList;
int gunNumVerts;
void readOBJ(const char* path)
{
FILE* f = fopen(path, "r");
float x[3];
unsigned short y[9];
std::vector<float>verts;
std::vector<float>uvs;
std::vector<float>norms;
std::vector<unsigned short>faces;
char line[100];
while (fgets(line, sizeof(line), f))
{
if (sscanf(line, "v %f %f %f", &x[0], &x[1], &x[2]) == 3)
{
for(int i = 0; i < 3; i++)
verts.push_back(x[i]);
}
if (sscanf(line, "vt %f %f", &x[0], &x[1]) == 2)
{
for(int i = 0; i < 2; i++)
uvs.push_back(x[i]);
}
if (sscanf(line, "vn %f %f %f", &x[0], &x[1], &x[2]) == 3)
{
for(int i = 0; i < 3; i++)
norms.push_back(x[i]);
}
if (sscanf(line, "f %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu", &y[0], &y[1], &y[2], &y[3], &y[4], &y[5], &y[6], &y[7], &y[8]) == 9)
{
for(int i = 0; i < 9; i++)
faces.push_back(y[i]-1);
}
}
int numFaces = faces.size()/9;
gunNumVerts = numFaces*3;
gunList = new Vertex[gunNumVerts];
for(int i = 0; i < (int)numFaces; i++)
{
for(int j = 0; j < 3; j++)
{
Vertex v;
for(int k = 0; k < 3; k++)
v.position[k] = verts[ 3*faces[9*i+3*j+0] +k];
v.texcoord[0] = uvs[ 2*faces[9*i+3*j+1] +0];
v.texcoord[1] = 1-uvs[ 2*faces[9*i+3*j+1] +1];
for(int k = 0; k < 3; k++)
v.normal[k] = norms[ 3*faces[9*i+3*j+2] +k];
gunList[3*i + j] = v;
}
}
fclose(f);
}
char* AmbOcc_png;
int AmbOcc_png_size;
char* Diffuse_png;
int Diffuse_png_size;
char* Normal_png;
int Normal_png_size;
char* Rough_png;
int Rough_png_size;
char* Specular_png;
int Specular_png_size;
static void sceneInit()
{
consoleInit(NULL);
romfsInit();
readPNG("romfs:/AmbOcc.png", &AmbOcc_png, &AmbOcc_png_size);
readPNG("romfs:/Diffuse.png", &Diffuse_png, &Diffuse_png_size);
readPNG("romfs:/Normal.png", &Normal_png, &Normal_png_size);
readPNG("romfs:/Rough.png", &Rough_png, &Rough_png_size);
readPNG("romfs:/Specular.png", &Specular_png, &Specular_png_size);
readOBJ("romfs:/gun.3Dobj");
//readOBJ("romfs:/cube.3Dobj");
GLint vsh = createAndCompileShader(GL_VERTEX_SHADER, vertexShaderSource);
GLint fsh = createAndCompileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
s_program = glCreateProgram();
glAttachShader(s_program, vsh);
glAttachShader(s_program, fsh);
glLinkProgram(s_program);
GLint success;
glGetProgramiv(s_program, GL_LINK_STATUS, &success);
if (success == GL_FALSE)
{
char buf[512];
glGetProgramInfoLog(s_program, sizeof(buf), nullptr, buf);
TRACE("Link error: %s", buf);
}
glDeleteShader(vsh);
glDeleteShader(fsh);
loc_mdlvMtx = glGetUniformLocation(s_program, "mdlvMtx");
loc_projMtx = glGetUniformLocation(s_program, "projMtx");
loc_lightPos = glGetUniformLocation(s_program, "lightPos");
loc_ambient = glGetUniformLocation(s_program, "lightAmbient");
loc_diffuse = glGetUniformLocation(s_program, "lightDiffuse");
loc_specular = glGetUniformLocation(s_program, "lightSpecular");
loc_tex_diffuse = glGetUniformLocation(s_program, "tex_diffuse");
loc_tex_specular = glGetUniformLocation(s_program, "tex_specular");
loc_tex_ambOcc = glGetUniformLocation(s_program, "tex_ambOcc");
loc_tex_normal = glGetUniformLocation(s_program, "tex_normal");
loc_tex_rough = glGetUniformLocation(s_program, "tex_rough");
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glGenVertexArrays(1, &s_vao);
glGenBuffers(1, &s_vbo);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(s_vao);
glBindBuffer(GL_ARRAY_BUFFER, s_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*gunNumVerts, gunList, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal));
glEnableVertexAttribArray(2);
// note that this is allowed, the call to glVertexAttribPointer registered VBO as the vertex attribute's bound vertex buffer object so afterwards we can safely unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
// You can unbind the VAO afterwards so other VAO calls won't accidentally modify this VAO, but this rarely happens. Modifying other
// VAOs requires a call to glBindVertexArray anyways so we generally don't unbind VAOs (nor VBOs) when it's not directly necessary.
glBindVertexArray(0);
int width, height, nchan;
stbi_uc* img;
// Textures
glGenTextures(1, &s_tex_diffuse);
glActiveTexture(GL_TEXTURE0); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, s_tex_diffuse);
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);
img = stbi_load_from_memory((const stbi_uc*)Diffuse_png, Diffuse_png_size, &width, &height, &nchan, 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
stbi_image_free(img);
// Textures
glGenTextures(1, &s_tex_specular);
glActiveTexture(GL_TEXTURE1); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, s_tex_specular);
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);
img = stbi_load_from_memory((const stbi_uc*)Specular_png, Specular_png_size, &width, &height, &nchan, 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
stbi_image_free(img);
// Textures
glGenTextures(1, &s_tex_ambOcc);
glActiveTexture(GL_TEXTURE2); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, s_tex_ambOcc);
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);
img = stbi_load_from_memory((const stbi_uc*)AmbOcc_png, AmbOcc_png_size, &width, &height, &nchan, 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
stbi_image_free(img);
// Textures
glGenTextures(1, &s_tex_normal);
glActiveTexture(GL_TEXTURE3); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, s_tex_normal);
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);
img = stbi_load_from_memory((const stbi_uc*)Normal_png, Normal_png_size, &width, &height, &nchan, 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
stbi_image_free(img);
// Textures
glGenTextures(1, &s_tex_rough);
glActiveTexture(GL_TEXTURE4); // activate the texture unit first before binding texture
glBindTexture(GL_TEXTURE_2D, s_tex_rough);
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);
img = stbi_load_from_memory((const stbi_uc*)Rough_png, Rough_png_size, &width, &height, &nchan, 4);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, img);
stbi_image_free(img);
// Uniforms
glUseProgram(s_program);
auto projMtx = glm::perspective(40.0f*TAU/360.0f, 1280.0f/720.0f, 0.01f, 1000.0f);
glUniformMatrix4fv(loc_projMtx, 1, GL_FALSE, glm::value_ptr(projMtx));
glUniform4f(loc_lightPos, 0.0f, 0.0f, 0.5f, 1.0f);
glUniform3f(loc_ambient, 0.5f, 0.5f, 0.5f);
glUniform3f(loc_diffuse, 0.2f, 0.2f, 1.0f);
glUniform4f(loc_specular, 0.3f, 0.3f, 0.3f, 16.0f);
glUniform1i(loc_tex_diffuse, 0); // GL_TEXTURE0make
glUniform1i(loc_tex_specular, 1); // GL_TEXTURE1
glUniform1i(loc_tex_ambOcc, 2);
glUniform1i(loc_tex_normal, 3);
glUniform1i(loc_tex_rough, 4);
s_startTicks = armGetSystemTick();
}
static float getTime()
{
u64 elapsed = armGetSystemTick() - s_startTicks;
return (elapsed * 625 / 12) / 1000000000.0;
}
static void sceneUpdate()
{
glm::mat4 mdlvMtx{1.0};
mdlvMtx = glm::translate(mdlvMtx, glm::vec3{0.0f, 0.0f, -2.0f});
//mdlvMtx = glm::rotate(mdlvMtx, getTime() * TAU * 0.00234375f, glm::vec3{1.0f, 0.0f, 0.0f});
mdlvMtx = glm::rotate(mdlvMtx, getTime() * TAU * 0.00234375f / 2.0f, glm::vec3{0.0f, 1.0f, 0.0f});
glUniformMatrix4fv(loc_mdlvMtx, 1, GL_FALSE, glm::value_ptr(mdlvMtx));
}
static void sceneRender()
{
glClearColor(0x68/255.0f, 0xB0/255.0f, 0xD8/255.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw our textured cube
glBindVertexArray(s_vao); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
glDrawArrays(GL_TRIANGLES, 0, gunNumVerts);
}
static void sceneExit()
{
glDeleteTextures(1, &s_tex_diffuse);
glDeleteTextures(1, &s_tex_specular);
glDeleteTextures(1, &s_tex_ambOcc);
glDeleteTextures(1, &s_tex_normal);
glDeleteTextures(1, &s_tex_rough);
glDeleteBuffers(1, &s_vbo);
glDeleteVertexArrays(1, &s_vao);
glDeleteProgram(s_program);
}
int main(int argc, char* argv[])
{
// Set mesa configuration (useful for debugging)
setMesaConfig();
// Initialize EGL on the default window
if (!initEgl(nwindowGetDefault()))
return EXIT_FAILURE;
// Load OpenGL routines using glad
gladLoadGL();
// Initialize our scene
sceneInit();
// Main graphics loop
while (appletMainLoop())
{
// Get and process input
hidScanInput();
u32 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
if (kDown & KEY_PLUS)
break;
// Update our scene
sceneUpdate();
// Render stuff!
sceneRender();
eglSwapBuffers(s_display, s_surface);
}
// Deinitialize our scene
sceneExit();
// Deinitialize EGL
deinitEgl();
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,3 @@
#define STBI_ONLY_PNG
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

File diff suppressed because it is too large Load Diff