sokol gfx extracted to lib
This commit is contained in:
		 Submodule 3rd-party updated: 1eec0920bb...ac6d28adc0
									
								
							
							
								
								
									
										122
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								CMakeLists.txt
									
									
									
									
									
								
							@@ -232,12 +232,16 @@ endif()
 | 
			
		||||
# Sokol
 | 
			
		||||
################################
 | 
			
		||||
 | 
			
		||||
set(SOKOL_LIB_SRC src/system/sokol_gfx.c)
 | 
			
		||||
 | 
			
		||||
if(APPLE)
 | 
			
		||||
    add_library(sokol src/ext/sokol_impl.m)
 | 
			
		||||
    set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} src/system/sokol_impl.m)
 | 
			
		||||
else()
 | 
			
		||||
	add_library(sokol src/ext/sokol_impl.c)
 | 
			
		||||
	set(SOKOL_LIB_SRC ${SOKOL_LIB_SRC} src/system/sokol_impl.c)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
add_library(sokol ${SOKOL_LIB_SRC})
 | 
			
		||||
 | 
			
		||||
if(APPLE)
 | 
			
		||||
	target_compile_definitions(sokol PRIVATE SOKOL_METAL)
 | 
			
		||||
elseif(WIN32)
 | 
			
		||||
@@ -246,10 +250,6 @@ elseif(LINUX)
 | 
			
		||||
	target_compile_definitions(sokol PRIVATE SOKOL_GLCORE33)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
	#set_source_files_properties(${SOKOL_SRC} PROPERTIES COMPILE_FLAGS -DSOKOL_METAL)
 | 
			
		||||
	# set_source_files_properties(${SOKOL_SRC} PROPERTIES COMPILE_FLAGS "-DSOKOL_D3D11 -DSOKOL_D3D11_SHADER_COMPILER")
 | 
			
		||||
	#set_source_files_properties(${SOKOL_SRC} PROPERTIES COMPILE_FLAGS -DSOKOL_GLCORE33)
 | 
			
		||||
 | 
			
		||||
if(APPLE)
 | 
			
		||||
	set_property (TARGET sokol APPEND_STRING PROPERTY 
 | 
			
		||||
    	COMPILE_FLAGS "-fobjc-arc")
 | 
			
		||||
@@ -292,15 +292,6 @@ if(MINGW)
 | 
			
		||||
	target_link_libraries(sokol-renderer mingw32)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
# TODO: remove this and define shaders in the sokol lib
 | 
			
		||||
if(APPLE)
 | 
			
		||||
	target_compile_definitions(sokol-renderer PRIVATE SOKOL_METAL)
 | 
			
		||||
elseif(WIN32)
 | 
			
		||||
	target_compile_definitions(sokol-renderer PRIVATE SOKOL_D3D11)
 | 
			
		||||
elseif(LINUX)
 | 
			
		||||
	target_compile_definitions(sokol-renderer PRIVATE SOKOL_GLCORE33)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
target_include_directories(sokol-renderer PRIVATE include)
 | 
			
		||||
target_include_directories(sokol-renderer PRIVATE 3rd-party/sokol)
 | 
			
		||||
target_include_directories(sokol-renderer PRIVATE src)
 | 
			
		||||
@@ -493,27 +484,15 @@ target_compile_definitions(tic80prolib PRIVATE TIC80_PRO)
 | 
			
		||||
# TIC-80 app
 | 
			
		||||
################################
 | 
			
		||||
 | 
			
		||||
set(TIC80_OUTPUTS ${TIC80_OUTPUTS} tic80-sokol tic80pro-sokol)
 | 
			
		||||
 | 
			
		||||
foreach(TIC80_OUTPUT ${TIC80_OUTPUTS})
 | 
			
		||||
 | 
			
		||||
	if(TIC80_OUTPUT MATCHES "-sokol")
 | 
			
		||||
		set(SOKOL_RENDERER TRUE)
 | 
			
		||||
	else() 
 | 
			
		||||
		set(SOKOL_RENDERER FALSE)
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
	set(TIC80_SRC src/ext/file_dialog.c)
 | 
			
		||||
 | 
			
		||||
	if(APPLE)
 | 
			
		||||
		set(TIC80_SRC ${TIC80_SRC} src/ext/file_dialog.m)
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
	if(SOKOL_RENDERER)
 | 
			
		||||
		set(TIC80_SRC ${TIC80_SRC} src/system/sokol.c)
 | 
			
		||||
	else()
 | 
			
		||||
		set(TIC80_SRC ${TIC80_SRC} src/net.c src/system/sdlgpu.c)
 | 
			
		||||
	endif()
 | 
			
		||||
	set(TIC80_SRC ${TIC80_SRC} src/net.c src/system/sdlgpu.c)
 | 
			
		||||
 | 
			
		||||
	if(WIN32)
 | 
			
		||||
		set(TIC80_SRC ${TIC80_SRC} build/windows/tic80.rc)
 | 
			
		||||
@@ -531,39 +510,20 @@ foreach(TIC80_OUTPUT ${TIC80_OUTPUTS})
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/SDL2_net-2.0.1)
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/SDL2-2.0.8/include)
 | 
			
		||||
 | 
			
		||||
	if(SOKOL_RENDERER)
 | 
			
		||||
		target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/sokol)
 | 
			
		||||
	else()
 | 
			
		||||
		target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/sdl-gpu/include)
 | 
			
		||||
	endif()
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT} PRIVATE 3rd-party/sdl-gpu/include)
 | 
			
		||||
 | 
			
		||||
	if(MINGW)
 | 
			
		||||
		target_link_libraries(${TIC80_OUTPUT} mingw32)
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
	if(SOKOL_RENDERER)
 | 
			
		||||
		# TODO fix Pro tic80lib
 | 
			
		||||
		add_dependencies(${TIC80_OUTPUT} tic80lib sokol)
 | 
			
		||||
		target_link_libraries(${TIC80_OUTPUT} tic80lib sokol)
 | 
			
		||||
 | 
			
		||||
		if(APPLE)
 | 
			
		||||
			target_compile_definitions(${TIC80_OUTPUT} PRIVATE SOKOL_METAL)
 | 
			
		||||
		elseif(WIN32)
 | 
			
		||||
			target_compile_definitions(${TIC80_OUTPUT} PRIVATE SOKOL_D3D11)
 | 
			
		||||
		elseif(LINUX)
 | 
			
		||||
			target_compile_definitions(${TIC80_OUTPUT} PRIVATE SOKOL_GLCORE33)
 | 
			
		||||
		endif()
 | 
			
		||||
 | 
			
		||||
	else()
 | 
			
		||||
		if(NOT EMSCRIPTEN)
 | 
			
		||||
			add_dependencies(${TIC80_OUTPUT} SDL2main SDL2-static)
 | 
			
		||||
			target_link_libraries(${TIC80_OUTPUT} SDL2-static SDL2main)
 | 
			
		||||
		endif()
 | 
			
		||||
 | 
			
		||||
		add_dependencies(${TIC80_OUTPUT} ${TIC80_OUTPUT}lib sdlnet sdlgpu)
 | 
			
		||||
		target_link_libraries(${TIC80_OUTPUT} ${TIC80_OUTPUT}lib sdlnet sdlgpu)
 | 
			
		||||
	if(NOT EMSCRIPTEN)
 | 
			
		||||
		add_dependencies(${TIC80_OUTPUT} SDL2main SDL2-static)
 | 
			
		||||
		target_link_libraries(${TIC80_OUTPUT} SDL2-static SDL2main)
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
	add_dependencies(${TIC80_OUTPUT} ${TIC80_OUTPUT}lib sdlnet sdlgpu)
 | 
			
		||||
	target_link_libraries(${TIC80_OUTPUT} ${TIC80_OUTPUT}lib sdlnet sdlgpu)
 | 
			
		||||
 | 
			
		||||
	if(LINUX)
 | 
			
		||||
		include(FindPkgConfig)
 | 
			
		||||
		if(NOT PKG_CONFIG_FOUND) 
 | 
			
		||||
@@ -577,3 +537,57 @@ foreach(TIC80_OUTPUT ${TIC80_OUTPUTS})
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
endforeach()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
################################
 | 
			
		||||
# TIC-80 app (Sokol)
 | 
			
		||||
################################
 | 
			
		||||
 | 
			
		||||
foreach(TIC80_OUTPUT ${TIC80_OUTPUTS})
 | 
			
		||||
 | 
			
		||||
	set(TIC80_SRC src/ext/file_dialog.c)
 | 
			
		||||
 | 
			
		||||
	if(APPLE)
 | 
			
		||||
		set(TIC80_SRC ${TIC80_SRC} src/ext/file_dialog.m)
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
	set(TIC80_SRC ${TIC80_SRC} src/system/sokol.c)
 | 
			
		||||
 | 
			
		||||
	if(WIN32)
 | 
			
		||||
		set(TIC80_SRC ${TIC80_SRC} build/windows/tic80.rc)
 | 
			
		||||
		add_executable(${TIC80_OUTPUT}-sokol WIN32 ${TIC80_SRC})
 | 
			
		||||
	elseif(APPLE)
 | 
			
		||||
		add_executable(${TIC80_OUTPUT} MACOSX_BUNDLE ${TIC80_SRC} build/macosx/tic80.icns)
 | 
			
		||||
		set_source_files_properties(build/macosx/tic80.icns PROPERTIES MACOSX_PACKAGE_LOCATION RESOURCES)
 | 
			
		||||
		set_target_properties(${TIC80_OUTPUT}-sokol PROPERTIES MACOSX_BUNDLE_INFO_PLIST build/macosx/${TIC80_OUTPUT}-sokol.plist)
 | 
			
		||||
	else()
 | 
			
		||||
		add_executable(${TIC80_OUTPUT}-sokol ${TIC80_SRC})
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE include)
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE src)
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE 3rd-party/SDL2_net-2.0.1)
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE 3rd-party/SDL2-2.0.8/include)
 | 
			
		||||
 | 
			
		||||
	target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE 3rd-party/sokol)
 | 
			
		||||
 | 
			
		||||
	if(MINGW)
 | 
			
		||||
		target_link_libraries(${TIC80_OUTPUT}-sokol mingw32)
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
	add_dependencies(${TIC80_OUTPUT}-sokol ${TIC80_OUTPUT}lib sokol)
 | 
			
		||||
	target_link_libraries(${TIC80_OUTPUT}-sokol ${TIC80_OUTPUT}lib sokol)
 | 
			
		||||
 | 
			
		||||
	if(LINUX)
 | 
			
		||||
		include(FindPkgConfig)
 | 
			
		||||
		if(NOT PKG_CONFIG_FOUND) 
 | 
			
		||||
			message(FATAL_ERROR "We need pkg-config to compile this project")
 | 
			
		||||
		endif()
 | 
			
		||||
 | 
			
		||||
		pkg_check_modules(GTK REQUIRED gtk+-3.0)
 | 
			
		||||
 | 
			
		||||
		target_include_directories(${TIC80_OUTPUT}-sokol PRIVATE ${GTK_INCLUDE_DIRS})
 | 
			
		||||
		target_link_libraries(${TIC80_OUTPUT}-sokol ${GTK_LIBRARIES})
 | 
			
		||||
	endif()
 | 
			
		||||
 | 
			
		||||
endforeach()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,4 @@
 | 
			
		||||
#include "sokol_app.h"
 | 
			
		||||
#include "sokol_gfx.h"
 | 
			
		||||
#include "sokol_time.h"
 | 
			
		||||
#include "sokol_audio.h"
 | 
			
		||||
#include "system/sokol.h"
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
@@ -12,247 +9,6 @@
 | 
			
		||||
 | 
			
		||||
static tic80* tic = NULL;
 | 
			
		||||
 | 
			
		||||
#if defined(SOKOL_GLCORE33)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "#version 330\n"
 | 
			
		||||
    "in vec2 in_pos;\n"
 | 
			
		||||
    "in vec2 in_uv;\n"
 | 
			
		||||
    "out vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  uv = in_uv;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "#version 330\n"
 | 
			
		||||
    "uniform sampler2D tex;\n"
 | 
			
		||||
    "in vec2 uv;\n"
 | 
			
		||||
    "out vec4 frag_color;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  frag_color = texture(tex, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_GLES2)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "attribute vec2 in_pos;\n"
 | 
			
		||||
    "attribute vec2 in_uv;\n"
 | 
			
		||||
    "varying vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  uv = in_uv;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "precision mediump float;\n"
 | 
			
		||||
    "uniform sampler2D tex;"
 | 
			
		||||
    "varying vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_FragColor = texture2D(tex, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_METAL)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "#include <metal_stdlib>\n"
 | 
			
		||||
    "using namespace metal;\n"
 | 
			
		||||
    "struct vs_in {\n"
 | 
			
		||||
    "  float2 pos [[attribute(0)]];\n"
 | 
			
		||||
    "  float2 uv [[attribute(1)]];\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "struct vs_out {\n"
 | 
			
		||||
    "  float4 pos [[position]];\n"
 | 
			
		||||
    "  float2 uv;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "vertex vs_out _main(vs_in in [[stage_in]]) {\n"
 | 
			
		||||
    "  vs_out out;\n"
 | 
			
		||||
    "  out.pos = float4(in.pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  out.uv = in.uv;\n"
 | 
			
		||||
    "  return out;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "#include <metal_stdlib>\n"
 | 
			
		||||
    "using namespace metal;\n"
 | 
			
		||||
    "struct fs_in {\n"
 | 
			
		||||
    "  float2 uv;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "fragment float4 _main(fs_in in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler smp [[sampler(0)]]) {\n"
 | 
			
		||||
    "  return tex.sample(smp, in.uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_D3D11)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "struct vs_in {\n"
 | 
			
		||||
    "  float2 pos: POS;\n"
 | 
			
		||||
    "  float2 uv:  UV;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "struct vs_out {\n"
 | 
			
		||||
    "  float2 uv: TEXCOORD0;\n"
 | 
			
		||||
    "  float4 pos: SV_Position;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "vs_out main(vs_in inp) {\n"
 | 
			
		||||
    "  vs_out outp;\n"
 | 
			
		||||
    "  outp.pos = float4(inp.pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  outp.uv = inp.uv;\n"
 | 
			
		||||
    "  return outp;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "Texture2D<float4> tex: register(t0);\n"
 | 
			
		||||
    "sampler smp: register(s0);\n"
 | 
			
		||||
    "float4 main(float2 uv: TEXCOORD0): SV_Target0 {\n"
 | 
			
		||||
    "  return tex.Sample(smp, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    sg_draw_state upscale_draw_state;
 | 
			
		||||
    sg_pass upscale_pass;
 | 
			
		||||
    sg_draw_state draw_state;
 | 
			
		||||
    int fb_width;
 | 
			
		||||
    int fb_height;
 | 
			
		||||
    int fb_aspect_scale_x;
 | 
			
		||||
    int fb_aspect_scale_y;
 | 
			
		||||
} gfx_state;
 | 
			
		||||
 | 
			
		||||
static gfx_state gfx;
 | 
			
		||||
 | 
			
		||||
void gfx_init(int w, int h, int sx, int sy) {
 | 
			
		||||
    gfx.fb_width = w;
 | 
			
		||||
    gfx.fb_height = h;
 | 
			
		||||
    gfx.fb_aspect_scale_x = sx;
 | 
			
		||||
    gfx.fb_aspect_scale_y = sy;
 | 
			
		||||
    sg_setup(&(sg_desc){
 | 
			
		||||
        .mtl_device = sapp_metal_get_device(),
 | 
			
		||||
        .mtl_renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor,
 | 
			
		||||
        .mtl_drawable_cb = sapp_metal_get_drawable,
 | 
			
		||||
        .d3d11_device = sapp_d3d11_get_device(),
 | 
			
		||||
        .d3d11_device_context = sapp_d3d11_get_device_context(),
 | 
			
		||||
        .d3d11_render_target_view_cb = sapp_d3d11_get_render_target_view,
 | 
			
		||||
        .d3d11_depth_stencil_view_cb = sapp_d3d11_get_depth_stencil_view
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* quad vertex buffers with and without flipped UVs */
 | 
			
		||||
    float verts[] = {
 | 
			
		||||
        0.0f, 0.0f, 0.0f, 0.0f,
 | 
			
		||||
        1.0f, 0.0f, 1.0f, 0.0f,
 | 
			
		||||
        0.0f, 1.0f, 0.0f, 1.0f,
 | 
			
		||||
        1.0f, 1.0f,  1.0f, 1.0f
 | 
			
		||||
    };
 | 
			
		||||
    float verts_flipped[] = {
 | 
			
		||||
        0.0f, 0.0f, 0.0f, 1.0f,
 | 
			
		||||
        1.0f, 0.0f, 1.0f, 1.0f,
 | 
			
		||||
        0.0f, 1.0f, 0.0f, 0.0f,
 | 
			
		||||
        1.0f, 1.0f,  1.0f, 0.0f
 | 
			
		||||
    };
 | 
			
		||||
    gfx.upscale_draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
 | 
			
		||||
        .size = sizeof(verts),
 | 
			
		||||
        .content = verts,
 | 
			
		||||
    });
 | 
			
		||||
    gfx.draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
 | 
			
		||||
        .size = sizeof(verts),
 | 
			
		||||
        .content = sg_query_feature(SG_FEATURE_ORIGIN_TOP_LEFT) ? verts : verts_flipped
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* a shader to render a textured quad */
 | 
			
		||||
    sg_shader fsq_shd = sg_make_shader(&(sg_shader_desc){
 | 
			
		||||
        .fs.images = {
 | 
			
		||||
            [0] = { .name="tex", .type=SG_IMAGETYPE_2D },
 | 
			
		||||
        },
 | 
			
		||||
        .vs.source = gfx_vs_src,
 | 
			
		||||
        .fs.source = gfx_fs_src,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* 2 pipeline-state-objects, one for upscaling, one for rendering */
 | 
			
		||||
    sg_pipeline_desc pip_desc = {
 | 
			
		||||
        .layout = {
 | 
			
		||||
            .attrs[0] = { .name="in_pos", .sem_name="POS", .format=SG_VERTEXFORMAT_FLOAT2 },
 | 
			
		||||
            .attrs[1] = { .name="in_uv", .sem_name="UV", .format=SG_VERTEXFORMAT_FLOAT2 }
 | 
			
		||||
        },
 | 
			
		||||
        .shader = fsq_shd,
 | 
			
		||||
        .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP
 | 
			
		||||
    };
 | 
			
		||||
    gfx.draw_state.pipeline = sg_make_pipeline(&pip_desc);
 | 
			
		||||
    pip_desc.blend.depth_format = SG_PIXELFORMAT_NONE;
 | 
			
		||||
    gfx.upscale_draw_state.pipeline = sg_make_pipeline(&pip_desc);
 | 
			
		||||
 | 
			
		||||
    /* a texture with the emulator's raw pixel data */
 | 
			
		||||
    gfx.upscale_draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){
 | 
			
		||||
        .width = gfx.fb_width,
 | 
			
		||||
        .height = gfx.fb_height,
 | 
			
		||||
        .pixel_format = SG_PIXELFORMAT_RGBA8,
 | 
			
		||||
        .usage = SG_USAGE_STREAM,
 | 
			
		||||
        .min_filter = SG_FILTER_NEAREST,
 | 
			
		||||
        .mag_filter = SG_FILTER_NEAREST,
 | 
			
		||||
        .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
 | 
			
		||||
        .wrap_v = SG_WRAP_CLAMP_TO_EDGE
 | 
			
		||||
    });
 | 
			
		||||
    /* a 2x upscaled render-target-texture */
 | 
			
		||||
    gfx.draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){
 | 
			
		||||
        .render_target = true,
 | 
			
		||||
        .width = 2*gfx.fb_width,
 | 
			
		||||
        .height = 2*gfx.fb_height,
 | 
			
		||||
        .pixel_format = SG_PIXELFORMAT_RGBA8,
 | 
			
		||||
        .min_filter = SG_FILTER_LINEAR,
 | 
			
		||||
        .mag_filter = SG_FILTER_LINEAR,
 | 
			
		||||
        .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
 | 
			
		||||
        .wrap_v = SG_WRAP_CLAMP_TO_EDGE
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* a render pass for the 2x upscaling */
 | 
			
		||||
    gfx.upscale_pass = sg_make_pass(&(sg_pass_desc){
 | 
			
		||||
        .color_attachments[0].image = gfx.draw_state.fs_images[0]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const sg_pass_action gfx_upscale_pass_action = {
 | 
			
		||||
    .colors[0] = { .action = SG_ACTION_DONTCARE }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const sg_pass_action gfx_draw_pass_action = {
 | 
			
		||||
    .colors[0] = { .action = SG_ACTION_CLEAR, .val = { 0.05f, 0.05f, 0.05f, 1.0f } }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void apply_viewport(void) {
 | 
			
		||||
    const int canvas_width = sapp_width();
 | 
			
		||||
    const int canvas_height = sapp_height();
 | 
			
		||||
    const float canvas_aspect = (float)canvas_width / (float)canvas_height;
 | 
			
		||||
    const float fb_aspect = (float)(gfx.fb_width*gfx.fb_aspect_scale_x) / (float)(gfx.fb_height*gfx.fb_aspect_scale_y);
 | 
			
		||||
    const int frame_x = 5;
 | 
			
		||||
    const int frame_y = 5;
 | 
			
		||||
    int vp_x, vp_y, vp_w, vp_h;
 | 
			
		||||
    if (fb_aspect < canvas_aspect) {
 | 
			
		||||
        vp_y = frame_y;
 | 
			
		||||
        vp_h = canvas_height - 2 * frame_y;
 | 
			
		||||
        vp_w = (int) (canvas_height * fb_aspect) - 2 * frame_x;
 | 
			
		||||
        vp_x = (canvas_width - vp_w) / 2;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        vp_x = frame_x;
 | 
			
		||||
        vp_w = canvas_width - 2 * frame_x;
 | 
			
		||||
        vp_h = (int) (canvas_width / fb_aspect) - 2 * frame_y;
 | 
			
		||||
        vp_y = frame_y;
 | 
			
		||||
    }
 | 
			
		||||
    sg_apply_viewport(vp_x, vp_y, vp_w, vp_h, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gfx_draw() {
 | 
			
		||||
 | 
			
		||||
    /* copy emulator pixel data into upscaling source texture */
 | 
			
		||||
    sg_update_image(gfx.upscale_draw_state.fs_images[0], &(sg_image_content){
 | 
			
		||||
        .subimage[0][0] = { 
 | 
			
		||||
            .ptr = tic->screen,
 | 
			
		||||
            .size = gfx.fb_width*gfx.fb_height*sizeof(uint32_t)
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* upscale the original framebuffer 2x with nearest filtering */
 | 
			
		||||
    sg_begin_pass(gfx.upscale_pass, &gfx_upscale_pass_action);
 | 
			
		||||
    sg_apply_draw_state(&gfx.upscale_draw_state);
 | 
			
		||||
    sg_draw(0, 4, 1);
 | 
			
		||||
    sg_end_pass();
 | 
			
		||||
 | 
			
		||||
    /* draw the final pass with linear filtering */
 | 
			
		||||
    sg_begin_default_pass(&gfx_draw_pass_action, sapp_width(), sapp_height());
 | 
			
		||||
    apply_viewport();
 | 
			
		||||
    sg_apply_draw_state(&gfx.draw_state);
 | 
			
		||||
    sg_draw(0, 4, 1);
 | 
			
		||||
    sg_end_pass();
 | 
			
		||||
    sg_commit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void app_init(void)
 | 
			
		||||
{
 | 
			
		||||
    saudio_desc desc = {0};
 | 
			
		||||
@@ -284,7 +40,7 @@ static void app_init(void)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1);
 | 
			
		||||
    sokol_gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static tic80_input tic_input;
 | 
			
		||||
@@ -294,7 +50,7 @@ static void app_frame(void)
 | 
			
		||||
    if(tic)
 | 
			
		||||
        tic80_tick(tic, tic_input);
 | 
			
		||||
 | 
			
		||||
    gfx_draw();
 | 
			
		||||
    sokol_gfx_draw(tic->screen);
 | 
			
		||||
 | 
			
		||||
    static float floatSamples[44100 / 60 * 2];
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,10 @@
 | 
			
		||||
#include <sokol_app.h>
 | 
			
		||||
#include <sokol_gfx.h>
 | 
			
		||||
#include <sokol_time.h>
 | 
			
		||||
#include <sokol_audio.h>
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <time.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
 | 
			
		||||
#include "system.h"
 | 
			
		||||
#include "system/sokol.h"
 | 
			
		||||
 | 
			
		||||
static struct
 | 
			
		||||
{
 | 
			
		||||
@@ -20,247 +16,8 @@ static struct
 | 
			
		||||
		float* samples;
 | 
			
		||||
	} audio;
 | 
			
		||||
 | 
			
		||||
	struct {
 | 
			
		||||
	    sg_draw_state upscale_draw_state;
 | 
			
		||||
	    sg_pass upscale_pass;
 | 
			
		||||
	    sg_draw_state draw_state;
 | 
			
		||||
	    s32 fb_width;
 | 
			
		||||
	    s32 fb_height;
 | 
			
		||||
	    s32 fb_aspect_scale_x;
 | 
			
		||||
	    s32 fb_aspect_scale_y;
 | 
			
		||||
	} gfx;
 | 
			
		||||
	
 | 
			
		||||
} platform;
 | 
			
		||||
 | 
			
		||||
#if defined(SOKOL_GLCORE33)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "#version 330\n"
 | 
			
		||||
    "in vec2 in_pos;\n"
 | 
			
		||||
    "in vec2 in_uv;\n"
 | 
			
		||||
    "out vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  uv = in_uv;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "#version 330\n"
 | 
			
		||||
    "uniform sampler2D tex;\n"
 | 
			
		||||
    "in vec2 uv;\n"
 | 
			
		||||
    "out vec4 frag_color;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  frag_color = texture(tex, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_GLES2)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "attribute vec2 in_pos;\n"
 | 
			
		||||
    "attribute vec2 in_uv;\n"
 | 
			
		||||
    "varying vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  uv = in_uv;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "precision mediump float;\n"
 | 
			
		||||
    "uniform sampler2D tex;"
 | 
			
		||||
    "varying vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_FragColor = texture2D(tex, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_METAL)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "#include <metal_stdlib>\n"
 | 
			
		||||
    "using namespace metal;\n"
 | 
			
		||||
    "struct vs_in {\n"
 | 
			
		||||
    "  float2 pos [[attribute(0)]];\n"
 | 
			
		||||
    "  float2 uv [[attribute(1)]];\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "struct vs_out {\n"
 | 
			
		||||
    "  float4 pos [[position]];\n"
 | 
			
		||||
    "  float2 uv;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "vertex vs_out _main(vs_in in [[stage_in]]) {\n"
 | 
			
		||||
    "  vs_out out;\n"
 | 
			
		||||
    "  out.pos = float4(in.pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  out.uv = in.uv;\n"
 | 
			
		||||
    "  return out;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "#include <metal_stdlib>\n"
 | 
			
		||||
    "using namespace metal;\n"
 | 
			
		||||
    "struct fs_in {\n"
 | 
			
		||||
    "  float2 uv;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "fragment float4 _main(fs_in in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler smp [[sampler(0)]]) {\n"
 | 
			
		||||
    "  return tex.sample(smp, in.uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_D3D11)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "struct vs_in {\n"
 | 
			
		||||
    "  float2 pos: POS;\n"
 | 
			
		||||
    "  float2 uv:  UV;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "struct vs_out {\n"
 | 
			
		||||
    "  float2 uv: TEXCOORD0;\n"
 | 
			
		||||
    "  float4 pos: SV_Position;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "vs_out main(vs_in inp) {\n"
 | 
			
		||||
    "  vs_out outp;\n"
 | 
			
		||||
    "  outp.pos = float4(inp.pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  outp.uv = inp.uv;\n"
 | 
			
		||||
    "  return outp;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "Texture2D<float4> tex: register(t0);\n"
 | 
			
		||||
    "sampler smp: register(s0);\n"
 | 
			
		||||
    "float4 main(float2 uv: TEXCOORD0): SV_Target0 {\n"
 | 
			
		||||
    "  return tex.Sample(smp, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void gfx_init(s32 w, s32 h, s32 sx, s32 sy) {
 | 
			
		||||
    platform.gfx.fb_width = w;
 | 
			
		||||
    platform.gfx.fb_height = h;
 | 
			
		||||
    platform.gfx.fb_aspect_scale_x = sx;
 | 
			
		||||
    platform.gfx.fb_aspect_scale_y = sy;
 | 
			
		||||
    sg_setup(&(sg_desc){
 | 
			
		||||
        .mtl_device = sapp_metal_get_device(),
 | 
			
		||||
        .mtl_renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor,
 | 
			
		||||
        .mtl_drawable_cb = sapp_metal_get_drawable,
 | 
			
		||||
        .d3d11_device = sapp_d3d11_get_device(),
 | 
			
		||||
        .d3d11_device_context = sapp_d3d11_get_device_context(),
 | 
			
		||||
        .d3d11_render_target_view_cb = sapp_d3d11_get_render_target_view,
 | 
			
		||||
        .d3d11_depth_stencil_view_cb = sapp_d3d11_get_depth_stencil_view
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* quad vertex buffers with and without flipped UVs */
 | 
			
		||||
    float verts[] = {
 | 
			
		||||
        0.0f, 0.0f, 0.0f, 0.0f,
 | 
			
		||||
        1.0f, 0.0f, 1.0f, 0.0f,
 | 
			
		||||
        0.0f, 1.0f, 0.0f, 1.0f,
 | 
			
		||||
        1.0f, 1.0f,  1.0f, 1.0f
 | 
			
		||||
    };
 | 
			
		||||
    float verts_flipped[] = {
 | 
			
		||||
        0.0f, 0.0f, 0.0f, 1.0f,
 | 
			
		||||
        1.0f, 0.0f, 1.0f, 1.0f,
 | 
			
		||||
        0.0f, 1.0f, 0.0f, 0.0f,
 | 
			
		||||
        1.0f, 1.0f,  1.0f, 0.0f
 | 
			
		||||
    };
 | 
			
		||||
    platform.gfx.upscale_draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
 | 
			
		||||
        .size = sizeof(verts),
 | 
			
		||||
        .content = verts,
 | 
			
		||||
    });
 | 
			
		||||
    platform.gfx.draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
 | 
			
		||||
        .size = sizeof(verts),
 | 
			
		||||
        .content = sg_query_feature(SG_FEATURE_ORIGIN_TOP_LEFT) ? verts : verts_flipped
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* a shader to render a textured quad */
 | 
			
		||||
    sg_shader fsq_shd = sg_make_shader(&(sg_shader_desc){
 | 
			
		||||
        .fs.images = {
 | 
			
		||||
            [0] = { .name="tex", .type=SG_IMAGETYPE_2D },
 | 
			
		||||
        },
 | 
			
		||||
        .vs.source = gfx_vs_src,
 | 
			
		||||
        .fs.source = gfx_fs_src,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* 2 pipeline-state-objects, one for upscaling, one for rendering */
 | 
			
		||||
    sg_pipeline_desc pip_desc = {
 | 
			
		||||
        .layout = {
 | 
			
		||||
            .attrs[0] = { .name="in_pos", .sem_name="POS", .format=SG_VERTEXFORMAT_FLOAT2 },
 | 
			
		||||
            .attrs[1] = { .name="in_uv", .sem_name="UV", .format=SG_VERTEXFORMAT_FLOAT2 }
 | 
			
		||||
        },
 | 
			
		||||
        .shader = fsq_shd,
 | 
			
		||||
        .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP
 | 
			
		||||
    };
 | 
			
		||||
    platform.gfx.draw_state.pipeline = sg_make_pipeline(&pip_desc);
 | 
			
		||||
    pip_desc.blend.depth_format = SG_PIXELFORMAT_NONE;
 | 
			
		||||
    platform.gfx.upscale_draw_state.pipeline = sg_make_pipeline(&pip_desc);
 | 
			
		||||
 | 
			
		||||
    /* a texture with the emulator's raw pixel data */
 | 
			
		||||
    platform.gfx.upscale_draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){
 | 
			
		||||
        .width = platform.gfx.fb_width,
 | 
			
		||||
        .height = platform.gfx.fb_height,
 | 
			
		||||
        .pixel_format = SG_PIXELFORMAT_RGBA8,
 | 
			
		||||
        .usage = SG_USAGE_STREAM,
 | 
			
		||||
        .min_filter = SG_FILTER_NEAREST,
 | 
			
		||||
        .mag_filter = SG_FILTER_NEAREST,
 | 
			
		||||
        .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
 | 
			
		||||
        .wrap_v = SG_WRAP_CLAMP_TO_EDGE
 | 
			
		||||
    });
 | 
			
		||||
    /* a 2x upscaled render-target-texture */
 | 
			
		||||
    platform.gfx.draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){
 | 
			
		||||
        .render_target = true,
 | 
			
		||||
        .width = 2*platform.gfx.fb_width,
 | 
			
		||||
        .height = 2*platform.gfx.fb_height,
 | 
			
		||||
        .pixel_format = SG_PIXELFORMAT_RGBA8,
 | 
			
		||||
        .min_filter = SG_FILTER_LINEAR,
 | 
			
		||||
        .mag_filter = SG_FILTER_LINEAR,
 | 
			
		||||
        .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
 | 
			
		||||
        .wrap_v = SG_WRAP_CLAMP_TO_EDGE
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* a render pass for the 2x upscaling */
 | 
			
		||||
    platform.gfx.upscale_pass = sg_make_pass(&(sg_pass_desc){
 | 
			
		||||
        .color_attachments[0].image = platform.gfx.draw_state.fs_images[0]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const sg_pass_action gfx_upscale_pass_action = {
 | 
			
		||||
    .colors[0] = { .action = SG_ACTION_DONTCARE }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const sg_pass_action gfx_draw_pass_action = {
 | 
			
		||||
    .colors[0] = { .action = SG_ACTION_CLEAR, .val = { 0.05f, 0.05f, 0.05f, 1.0f } }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void apply_viewport(void) {
 | 
			
		||||
    const s32 canvas_width = sapp_width();
 | 
			
		||||
    const s32 canvas_height = sapp_height();
 | 
			
		||||
    const float canvas_aspect = (float)canvas_width / (float)canvas_height;
 | 
			
		||||
    const float fb_aspect = (float)(platform.gfx.fb_width*platform.gfx.fb_aspect_scale_x) / (float)(platform.gfx.fb_height*platform.gfx.fb_aspect_scale_y);
 | 
			
		||||
    const s32 frame_x = 5;
 | 
			
		||||
    const s32 frame_y = 5;
 | 
			
		||||
    s32 vp_x, vp_y, vp_w, vp_h;
 | 
			
		||||
    if (fb_aspect < canvas_aspect) {
 | 
			
		||||
        vp_y = frame_y;
 | 
			
		||||
        vp_h = canvas_height - 2 * frame_y;
 | 
			
		||||
        vp_w = (s32) (canvas_height * fb_aspect) - 2 * frame_x;
 | 
			
		||||
        vp_x = (canvas_width - vp_w) / 2;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        vp_x = frame_x;
 | 
			
		||||
        vp_w = canvas_width - 2 * frame_x;
 | 
			
		||||
        vp_h = (s32) (canvas_width / fb_aspect) - 2 * frame_y;
 | 
			
		||||
        vp_y = frame_y;
 | 
			
		||||
    }
 | 
			
		||||
    sg_apply_viewport(vp_x, vp_y, vp_w, vp_h, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gfx_draw() {
 | 
			
		||||
 | 
			
		||||
    /* copy emulator pixel data into upscaling source texture */
 | 
			
		||||
    sg_update_image(platform.gfx.upscale_draw_state.fs_images[0], &(sg_image_content){
 | 
			
		||||
        .subimage[0][0] = { 
 | 
			
		||||
            .ptr = platform.studio->tic->screen,
 | 
			
		||||
            .size = platform.gfx.fb_width*platform.gfx.fb_height*sizeof platform.studio->tic->screen[0]
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* upscale the original framebuffer 2x with nearest filtering */
 | 
			
		||||
    sg_begin_pass(platform.gfx.upscale_pass, &gfx_upscale_pass_action);
 | 
			
		||||
    sg_apply_draw_state(&platform.gfx.upscale_draw_state);
 | 
			
		||||
    sg_draw(0, 4, 1);
 | 
			
		||||
    sg_end_pass();
 | 
			
		||||
 | 
			
		||||
    /* draw the final pass with linear filtering */
 | 
			
		||||
    sg_begin_default_pass(&gfx_draw_pass_action, sapp_width(), sapp_height());
 | 
			
		||||
    apply_viewport();
 | 
			
		||||
    sg_apply_draw_state(&platform.gfx.draw_state);
 | 
			
		||||
    sg_draw(0, 4, 1);
 | 
			
		||||
    sg_end_pass();
 | 
			
		||||
    sg_commit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void setClipboardText(const char* text)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
@@ -359,7 +116,7 @@ static System systemInterface =
 | 
			
		||||
 | 
			
		||||
static void app_init(void)
 | 
			
		||||
{
 | 
			
		||||
	gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1);
 | 
			
		||||
	sokol_gfx_init(TIC80_FULLWIDTH, TIC80_FULLHEIGHT, 1, 1);
 | 
			
		||||
 | 
			
		||||
    platform.audio.samples = calloc(sizeof platform.audio.samples[0], saudio_sample_rate() / TIC_FRAMERATE * TIC_STEREO_CHANNLES);
 | 
			
		||||
}
 | 
			
		||||
@@ -375,7 +132,7 @@ static void app_frame(void)
 | 
			
		||||
 | 
			
		||||
	platform.studio->tick();
 | 
			
		||||
 | 
			
		||||
	gfx_draw();
 | 
			
		||||
	sokol_gfx_draw(platform.studio->tic->screen);
 | 
			
		||||
 | 
			
		||||
	s32 count = tic->samples.size / sizeof tic->samples.buffer[0];
 | 
			
		||||
    for(s32 i = 0; i < count; i++)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										11
									
								
								src/system/sokol.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/system/sokol.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "sokol_app.h"
 | 
			
		||||
#include "sokol_gfx.h"
 | 
			
		||||
#include "sokol_time.h"
 | 
			
		||||
#include "sokol_audio.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
void sokol_gfx_init(int w, int h, int sx, int sy);
 | 
			
		||||
void sokol_gfx_draw(const uint32_t* ptr);
 | 
			
		||||
							
								
								
									
										246
									
								
								src/system/sokol_gfx.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								src/system/sokol_gfx.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,246 @@
 | 
			
		||||
#include "sokol.h"
 | 
			
		||||
 | 
			
		||||
static struct 
 | 
			
		||||
{
 | 
			
		||||
	sg_draw_state upscale_draw_state;
 | 
			
		||||
	sg_pass upscale_pass;
 | 
			
		||||
	sg_draw_state draw_state;
 | 
			
		||||
	int fb_width;
 | 
			
		||||
	int fb_height;
 | 
			
		||||
	int fb_aspect_scale_x;
 | 
			
		||||
	int fb_aspect_scale_y;
 | 
			
		||||
} sokol_gfx;
 | 
			
		||||
 | 
			
		||||
#if defined(SOKOL_GLCORE33)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "#version 330\n"
 | 
			
		||||
    "in vec2 in_pos;\n"
 | 
			
		||||
    "in vec2 in_uv;\n"
 | 
			
		||||
    "out vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  uv = in_uv;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "#version 330\n"
 | 
			
		||||
    "uniform sampler2D tex;\n"
 | 
			
		||||
    "in vec2 uv;\n"
 | 
			
		||||
    "out vec4 frag_color;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  frag_color = texture(tex, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_GLES2)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "attribute vec2 in_pos;\n"
 | 
			
		||||
    "attribute vec2 in_uv;\n"
 | 
			
		||||
    "varying vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_Position = vec4(in_pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  uv = in_uv;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "precision mediump float;\n"
 | 
			
		||||
    "uniform sampler2D tex;"
 | 
			
		||||
    "varying vec2 uv;\n"
 | 
			
		||||
    "void main() {\n"
 | 
			
		||||
    "  gl_FragColor = texture2D(tex, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_METAL)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "#include <metal_stdlib>\n"
 | 
			
		||||
    "using namespace metal;\n"
 | 
			
		||||
    "struct vs_in {\n"
 | 
			
		||||
    "  float2 pos [[attribute(0)]];\n"
 | 
			
		||||
    "  float2 uv [[attribute(1)]];\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "struct vs_out {\n"
 | 
			
		||||
    "  float4 pos [[position]];\n"
 | 
			
		||||
    "  float2 uv;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "vertex vs_out _main(vs_in in [[stage_in]]) {\n"
 | 
			
		||||
    "  vs_out out;\n"
 | 
			
		||||
    "  out.pos = float4(in.pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  out.uv = in.uv;\n"
 | 
			
		||||
    "  return out;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "#include <metal_stdlib>\n"
 | 
			
		||||
    "using namespace metal;\n"
 | 
			
		||||
    "struct fs_in {\n"
 | 
			
		||||
    "  float2 uv;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "fragment float4 _main(fs_in in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler smp [[sampler(0)]]) {\n"
 | 
			
		||||
    "  return tex.sample(smp, in.uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#elif defined(SOKOL_D3D11)
 | 
			
		||||
static const char* gfx_vs_src =
 | 
			
		||||
    "struct vs_in {\n"
 | 
			
		||||
    "  float2 pos: POS;\n"
 | 
			
		||||
    "  float2 uv:  UV;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "struct vs_out {\n"
 | 
			
		||||
    "  float2 uv: TEXCOORD0;\n"
 | 
			
		||||
    "  float4 pos: SV_Position;\n"
 | 
			
		||||
    "};\n"
 | 
			
		||||
    "vs_out main(vs_in inp) {\n"
 | 
			
		||||
    "  vs_out outp;\n"
 | 
			
		||||
    "  outp.pos = float4(inp.pos*2.0-1.0, 0.5, 1.0);\n"
 | 
			
		||||
    "  outp.uv = inp.uv;\n"
 | 
			
		||||
    "  return outp;\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
static const char* gfx_fs_src =
 | 
			
		||||
    "Texture2D<float4> tex: register(t0);\n"
 | 
			
		||||
    "sampler smp: register(s0);\n"
 | 
			
		||||
    "float4 main(float2 uv: TEXCOORD0): SV_Target0 {\n"
 | 
			
		||||
    "  return tex.Sample(smp, uv);\n"
 | 
			
		||||
    "}\n";
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void sokol_gfx_init(int w, int h, int sx, int sy) {
 | 
			
		||||
    sokol_gfx.fb_width = w;
 | 
			
		||||
    sokol_gfx.fb_height = h;
 | 
			
		||||
    sokol_gfx.fb_aspect_scale_x = sx;
 | 
			
		||||
    sokol_gfx.fb_aspect_scale_y = sy;
 | 
			
		||||
    sg_setup(&(sg_desc){
 | 
			
		||||
        .mtl_device = sapp_metal_get_device(),
 | 
			
		||||
        .mtl_renderpass_descriptor_cb = sapp_metal_get_renderpass_descriptor,
 | 
			
		||||
        .mtl_drawable_cb = sapp_metal_get_drawable,
 | 
			
		||||
        .d3d11_device = sapp_d3d11_get_device(),
 | 
			
		||||
        .d3d11_device_context = sapp_d3d11_get_device_context(),
 | 
			
		||||
        .d3d11_render_target_view_cb = sapp_d3d11_get_render_target_view,
 | 
			
		||||
        .d3d11_depth_stencil_view_cb = sapp_d3d11_get_depth_stencil_view
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* quad vertex buffers with and without flipped UVs */
 | 
			
		||||
    float verts[] = {
 | 
			
		||||
        0.0f, 0.0f, 0.0f, 0.0f,
 | 
			
		||||
        1.0f, 0.0f, 1.0f, 0.0f,
 | 
			
		||||
        0.0f, 1.0f, 0.0f, 1.0f,
 | 
			
		||||
        1.0f, 1.0f,  1.0f, 1.0f
 | 
			
		||||
    };
 | 
			
		||||
    float verts_flipped[] = {
 | 
			
		||||
        0.0f, 0.0f, 0.0f, 1.0f,
 | 
			
		||||
        1.0f, 0.0f, 1.0f, 1.0f,
 | 
			
		||||
        0.0f, 1.0f, 0.0f, 0.0f,
 | 
			
		||||
        1.0f, 1.0f,  1.0f, 0.0f
 | 
			
		||||
    };
 | 
			
		||||
    sokol_gfx.upscale_draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
 | 
			
		||||
        .size = sizeof(verts),
 | 
			
		||||
        .content = verts,
 | 
			
		||||
    });
 | 
			
		||||
    sokol_gfx.draw_state.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
 | 
			
		||||
        .size = sizeof(verts),
 | 
			
		||||
        .content = sg_query_feature(SG_FEATURE_ORIGIN_TOP_LEFT) ? verts : verts_flipped
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* a shader to render a textured quad */
 | 
			
		||||
    sg_shader fsq_shd = sg_make_shader(&(sg_shader_desc){
 | 
			
		||||
        .fs.images = {
 | 
			
		||||
            [0] = { .name="tex", .type=SG_IMAGETYPE_2D },
 | 
			
		||||
        },
 | 
			
		||||
        .vs.source = gfx_vs_src,
 | 
			
		||||
        .fs.source = gfx_fs_src,
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* 2 pipeline-state-objects, one for upscaling, one for rendering */
 | 
			
		||||
    sg_pipeline_desc pip_desc = {
 | 
			
		||||
        .layout = {
 | 
			
		||||
            .attrs[0] = { .name="in_pos", .sem_name="POS", .format=SG_VERTEXFORMAT_FLOAT2 },
 | 
			
		||||
            .attrs[1] = { .name="in_uv", .sem_name="UV", .format=SG_VERTEXFORMAT_FLOAT2 }
 | 
			
		||||
        },
 | 
			
		||||
        .shader = fsq_shd,
 | 
			
		||||
        .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP
 | 
			
		||||
    };
 | 
			
		||||
    sokol_gfx.draw_state.pipeline = sg_make_pipeline(&pip_desc);
 | 
			
		||||
    pip_desc.blend.depth_format = SG_PIXELFORMAT_NONE;
 | 
			
		||||
    sokol_gfx.upscale_draw_state.pipeline = sg_make_pipeline(&pip_desc);
 | 
			
		||||
 | 
			
		||||
    /* a texture with the emulator's raw pixel data */
 | 
			
		||||
    sokol_gfx.upscale_draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){
 | 
			
		||||
        .width = sokol_gfx.fb_width,
 | 
			
		||||
        .height = sokol_gfx.fb_height,
 | 
			
		||||
        .pixel_format = SG_PIXELFORMAT_RGBA8,
 | 
			
		||||
        .usage = SG_USAGE_STREAM,
 | 
			
		||||
        .min_filter = SG_FILTER_NEAREST,
 | 
			
		||||
        .mag_filter = SG_FILTER_NEAREST,
 | 
			
		||||
        .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
 | 
			
		||||
        .wrap_v = SG_WRAP_CLAMP_TO_EDGE
 | 
			
		||||
    });
 | 
			
		||||
    /* a 2x upscaled render-target-texture */
 | 
			
		||||
    sokol_gfx.draw_state.fs_images[0] = sg_make_image(&(sg_image_desc){
 | 
			
		||||
        .render_target = true,
 | 
			
		||||
        .width = 2*sokol_gfx.fb_width,
 | 
			
		||||
        .height = 2*sokol_gfx.fb_height,
 | 
			
		||||
        .pixel_format = SG_PIXELFORMAT_RGBA8,
 | 
			
		||||
        .min_filter = SG_FILTER_LINEAR,
 | 
			
		||||
        .mag_filter = SG_FILTER_LINEAR,
 | 
			
		||||
        .wrap_u = SG_WRAP_CLAMP_TO_EDGE,
 | 
			
		||||
        .wrap_v = SG_WRAP_CLAMP_TO_EDGE
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* a render pass for the 2x upscaling */
 | 
			
		||||
    sokol_gfx.upscale_pass = sg_make_pass(&(sg_pass_desc){
 | 
			
		||||
        .color_attachments[0].image = sokol_gfx.draw_state.fs_images[0]
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const sg_pass_action gfx_upscale_pass_action = {
 | 
			
		||||
    .colors[0] = { .action = SG_ACTION_DONTCARE }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const sg_pass_action gfx_draw_pass_action = {
 | 
			
		||||
    .colors[0] = { .action = SG_ACTION_CLEAR, .val = { 0.05f, 0.05f, 0.05f, 1.0f } }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void apply_viewport(void) {
 | 
			
		||||
    const int canvas_width = sapp_width();
 | 
			
		||||
    const int canvas_height = sapp_height();
 | 
			
		||||
    const float canvas_aspect = (float)canvas_width / (float)canvas_height;
 | 
			
		||||
    const float fb_aspect = (float)(sokol_gfx.fb_width*sokol_gfx.fb_aspect_scale_x) / (float)(sokol_gfx.fb_height*sokol_gfx.fb_aspect_scale_y);
 | 
			
		||||
    const int frame_x = 5;
 | 
			
		||||
    const int frame_y = 5;
 | 
			
		||||
    int vp_x, vp_y, vp_w, vp_h;
 | 
			
		||||
    if (fb_aspect < canvas_aspect) {
 | 
			
		||||
        vp_y = frame_y;
 | 
			
		||||
        vp_h = canvas_height - 2 * frame_y;
 | 
			
		||||
        vp_w = (int) (canvas_height * fb_aspect) - 2 * frame_x;
 | 
			
		||||
        vp_x = (canvas_width - vp_w) / 2;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        vp_x = frame_x;
 | 
			
		||||
        vp_w = canvas_width - 2 * frame_x;
 | 
			
		||||
        vp_h = (int) (canvas_width / fb_aspect) - 2 * frame_y;
 | 
			
		||||
 | 
			
		||||
        // align top
 | 
			
		||||
        // vp_y = frame_y;
 | 
			
		||||
 | 
			
		||||
        // align vcenter
 | 
			
		||||
        vp_y = (canvas_height - vp_h) / 2;
 | 
			
		||||
    }
 | 
			
		||||
    sg_apply_viewport(vp_x, vp_y, vp_w, vp_h, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sokol_gfx_draw(const uint32_t* ptr) {
 | 
			
		||||
 | 
			
		||||
    /* copy emulator pixel data into upscaling source texture */
 | 
			
		||||
    sg_update_image(sokol_gfx.upscale_draw_state.fs_images[0], &(sg_image_content){
 | 
			
		||||
        .subimage[0][0] = { 
 | 
			
		||||
            .ptr = ptr,
 | 
			
		||||
            .size = sokol_gfx.fb_width*sokol_gfx.fb_height*sizeof ptr[0]
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    /* upscale the original framebuffer 2x with nearest filtering */
 | 
			
		||||
    sg_begin_pass(sokol_gfx.upscale_pass, &gfx_upscale_pass_action);
 | 
			
		||||
    sg_apply_draw_state(&sokol_gfx.upscale_draw_state);
 | 
			
		||||
    sg_draw(0, 4, 1);
 | 
			
		||||
    sg_end_pass();
 | 
			
		||||
 | 
			
		||||
    /* draw the final pass with linear filtering */
 | 
			
		||||
    sg_begin_default_pass(&gfx_draw_pass_action, sapp_width(), sapp_height());
 | 
			
		||||
    apply_viewport();
 | 
			
		||||
    sg_apply_draw_state(&sokol_gfx.draw_state);
 | 
			
		||||
    sg_draw(0, 4, 1);
 | 
			
		||||
    sg_end_pass();
 | 
			
		||||
    sg_commit();
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user