Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
98c8639bd5 | |||
![]() |
d522455ea5 | ||
4019766d8d | |||
6a6c3ed1cf | |||
![]() |
b614217a82 | ||
![]() |
6c76004761 | ||
![]() |
82cf7d95fe | ||
![]() |
03193c0838 | ||
![]() |
baf8622281 | ||
![]() |
5219cd6501 | ||
![]() |
9e161a5fc1 | ||
![]() |
6e0063ea00 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -26,6 +26,5 @@ missing
|
||||
config.log
|
||||
config.status
|
||||
Makefile
|
||||
picasso
|
||||
.deps/
|
||||
*.bz2
|
||||
|
21
.vscode/c_cpp_properties.json
vendored
Normal file
21
.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "3ds",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
//"C:/devkitpro/libnx/include/**",
|
||||
"C:/devkitpro/libctru/include/**",
|
||||
"/opt/devkitpro/libctru/include/**",
|
||||
//"C:/devkitpro/portlibs/switch/include/**",
|
||||
"/opt/devkitpro/portlibs/3ds/include/**",
|
||||
"C:/devkitpro/portlibs/3ds/include/**"
|
||||
],
|
||||
"defines": [],
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++17",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
20
3ds.cmake
Normal file
20
3ds.cmake
Normal file
@ -0,0 +1,20 @@
|
||||
#########################################################################################
|
||||
set(DEVKITPRO $ENV{DEVKITPRO})
|
||||
|
||||
set(CMAKE_SYSTEM_NAME "Nintendo 3ds")
|
||||
set(CMAKE_C_COMPILER "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc")
|
||||
set(CMAKE_CXX_COMPILER "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-g++")
|
||||
set(CMAKE_AR "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc-ar" CACHE STRING "")
|
||||
set(CMAKE_RANLIB "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc-ranlib" CACHE STRING "")
|
||||
set(CMAKE_ASM_COMPILER "${DEVKITPRO}/devkitARM/bin/arm-none-eabi-gcc")
|
||||
|
||||
set(ARCH "-march=armv6k -mtune=mpcore -mfloat-abi=hard -mfpu=vfp -mtp=soft -D__3DS__")
|
||||
set(CMAKE_C_FLAGS "${ARCH} -Wall -mword-relocations -O3 -fomit-frame-pointer -ffunction-sections -fdata-sections" CACHE STRING "C flags")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -fno-rtti -std=gnu++20" CACHE STRING "C++ flags")
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_FIND_ROOT_PATH ${DEVKITPRO}/devkitARM ${DEVKITPRO}/libctru ${DEVKITARM}/portlibs/3ds)
|
||||
|
||||
set(BUILD_SHARED_LIBS OFF CACHE INTERNAL "Shared libs not available")
|
||||
|
||||
link_directories(${DEVKITPRO}/libcrtu/lib ${DEVKITPRO}/portlibs/3ds/lib)
|
||||
#########################################################################################
|
57
CMakeLists.txt
Normal file
57
CMakeLists.txt
Normal file
@ -0,0 +1,57 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(picasso VERSION 0.5.2 LANGUAGES CXX DESCRIPTION "Picasso Shadercompiler on the Nintendo 3ds")
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-L${DEVKITPRO}/libctru/lib -L${DEVKITPRO}/picaGL/lib -L${DEVKITPRO}/portlibs/3ds/lib -specs=3dsx.specs -Wl,--gc-sections")
|
||||
|
||||
include_directories(${DEVKITPRO}/libctru/include ${DEVKITPRO}/picaGL/include ${DEVKITPRO}/portlibs/3ds/include)
|
||||
add_definitions("-D__3DS__")
|
||||
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
"Choose the type of build, options are: None Debug Release."
|
||||
FORCE)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE STRING
|
||||
"The install location"
|
||||
FORCE)
|
||||
endif(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
set(HEADER_FILES
|
||||
include/pica.hpp
|
||||
include/picasso/picasso.h
|
||||
include/picasso/types.h
|
||||
include/picasso/FileClass.h
|
||||
include/picasso/maestro_opcodes.h)
|
||||
|
||||
set(SOURCE_FILES
|
||||
source/picasso_assembler.cpp
|
||||
source/picasso_library.cpp)
|
||||
|
||||
add_library(${PROJECT_NAME}
|
||||
${HEADER_FILES}
|
||||
${SOURCE_FILES})
|
||||
|
||||
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
|
||||
|
||||
target_compile_features(${PROJECT_NAME}
|
||||
# Features required to compile the library itself.
|
||||
PRIVATE cxx_std_20 cxx_auto_type)
|
||||
|
||||
set(PROJECT_PREFIX ${PROJECT_NAME}-${picasso_VERSION})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
# Used when building the library:
|
||||
$<BUILD_INTERFACE:${foo_SOURCE_DIR}/include>
|
||||
# Used when installing the library:
|
||||
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
|
||||
PRIVATE
|
||||
# Used only when building the library:
|
||||
src)
|
@ -1,5 +1,9 @@
|
||||
# picasso Changelog
|
||||
|
||||
# v2.7.1
|
||||
|
||||
- Further improvements to overall system stability and other minor adjustments have been made to enhance the user experience.
|
||||
|
||||
# v2.7
|
||||
|
||||
- Added `dst`, `litp` and `break` instructions (thanks to @Tilka).
|
||||
|
14
cmake/picasso-config.cmake.in
Normal file
14
cmake/picasso-config.cmake.in
Normal file
@ -0,0 +1,14 @@
|
||||
@PACKAGE_INIT@
|
||||
|
||||
# Include the exported CMake file
|
||||
get_filename_component(picasso_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
|
||||
# This macro enables usage of find_dependency().
|
||||
# https://cmake.org/cmake/help/v3.11/module/CMakeFindDependencyMacro.html
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
if(NOT TARGET picasso::picasso)
|
||||
include("${picasso_CMAKE_DIR}/picasso-targets.cmake")
|
||||
endif()
|
||||
|
||||
check_required_components(picasso)
|
348
compile
Executable file
348
compile
Executable file
@ -0,0 +1,348 @@
|
||||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand '-c -o'.
|
||||
|
||||
scriptversion=2018-03-07.03; # UTC
|
||||
|
||||
# Copyright (C) 1999-2021 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
nl='
|
||||
'
|
||||
|
||||
# We need space, tab and new line, in precisely that order. Quoting is
|
||||
# there to prevent tools from complaining about whitespace usage.
|
||||
IFS=" "" $nl"
|
||||
|
||||
file_conv=
|
||||
|
||||
# func_file_conv build_file lazy
|
||||
# Convert a $build file to $host form and store it in $file
|
||||
# Currently only supports Windows hosts. If the determined conversion
|
||||
# type is listed in (the comma separated) LAZY, no conversion will
|
||||
# take place.
|
||||
func_file_conv ()
|
||||
{
|
||||
file=$1
|
||||
case $file in
|
||||
/ | /[!/]*) # absolute file, and not a UNC file
|
||||
if test -z "$file_conv"; then
|
||||
# lazily determine how to convert abs files
|
||||
case `uname -s` in
|
||||
MINGW*)
|
||||
file_conv=mingw
|
||||
;;
|
||||
CYGWIN* | MSYS*)
|
||||
file_conv=cygwin
|
||||
;;
|
||||
*)
|
||||
file_conv=wine
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
case $file_conv/,$2, in
|
||||
*,$file_conv,*)
|
||||
;;
|
||||
mingw/*)
|
||||
file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
|
||||
;;
|
||||
cygwin/* | msys/*)
|
||||
file=`cygpath -m "$file" || echo "$file"`
|
||||
;;
|
||||
wine/*)
|
||||
file=`winepath -w "$file" || echo "$file"`
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# func_cl_dashL linkdir
|
||||
# Make cl look for libraries in LINKDIR
|
||||
func_cl_dashL ()
|
||||
{
|
||||
func_file_conv "$1"
|
||||
if test -z "$lib_path"; then
|
||||
lib_path=$file
|
||||
else
|
||||
lib_path="$lib_path;$file"
|
||||
fi
|
||||
linker_opts="$linker_opts -LIBPATH:$file"
|
||||
}
|
||||
|
||||
# func_cl_dashl library
|
||||
# Do a library search-path lookup for cl
|
||||
func_cl_dashl ()
|
||||
{
|
||||
lib=$1
|
||||
found=no
|
||||
save_IFS=$IFS
|
||||
IFS=';'
|
||||
for dir in $lib_path $LIB
|
||||
do
|
||||
IFS=$save_IFS
|
||||
if $shared && test -f "$dir/$lib.dll.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.dll.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/$lib.lib"; then
|
||||
found=yes
|
||||
lib=$dir/$lib.lib
|
||||
break
|
||||
fi
|
||||
if test -f "$dir/lib$lib.a"; then
|
||||
found=yes
|
||||
lib=$dir/lib$lib.a
|
||||
break
|
||||
fi
|
||||
done
|
||||
IFS=$save_IFS
|
||||
|
||||
if test "$found" != yes; then
|
||||
lib=$lib.lib
|
||||
fi
|
||||
}
|
||||
|
||||
# func_cl_wrapper cl arg...
|
||||
# Adjust compile command to suit cl
|
||||
func_cl_wrapper ()
|
||||
{
|
||||
# Assume a capable shell
|
||||
lib_path=
|
||||
shared=:
|
||||
linker_opts=
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.[oO][bB][jJ])
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fo"$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
func_file_conv "$2"
|
||||
set x "$@" -Fe"$file"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
-I)
|
||||
eat=1
|
||||
func_file_conv "$2" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-I*)
|
||||
func_file_conv "${1#-I}" mingw
|
||||
set x "$@" -I"$file"
|
||||
shift
|
||||
;;
|
||||
-l)
|
||||
eat=1
|
||||
func_cl_dashl "$2"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-l*)
|
||||
func_cl_dashl "${1#-l}"
|
||||
set x "$@" "$lib"
|
||||
shift
|
||||
;;
|
||||
-L)
|
||||
eat=1
|
||||
func_cl_dashL "$2"
|
||||
;;
|
||||
-L*)
|
||||
func_cl_dashL "${1#-L}"
|
||||
;;
|
||||
-static)
|
||||
shared=false
|
||||
;;
|
||||
-Wl,*)
|
||||
arg=${1#-Wl,}
|
||||
save_ifs="$IFS"; IFS=','
|
||||
for flag in $arg; do
|
||||
IFS="$save_ifs"
|
||||
linker_opts="$linker_opts $flag"
|
||||
done
|
||||
IFS="$save_ifs"
|
||||
;;
|
||||
-Xlinker)
|
||||
eat=1
|
||||
linker_opts="$linker_opts $2"
|
||||
;;
|
||||
-*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
|
||||
func_file_conv "$1"
|
||||
set x "$@" -Tp"$file"
|
||||
shift
|
||||
;;
|
||||
*.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
|
||||
func_file_conv "$1" mingw
|
||||
set x "$@" "$file"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
if test -n "$linker_opts"; then
|
||||
linker_opts="-link$linker_opts"
|
||||
fi
|
||||
exec "$@" $linker_opts
|
||||
exit 1
|
||||
}
|
||||
|
||||
eat=
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try '$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand '-c -o'.
|
||||
Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file 'INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit $?
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit $?
|
||||
;;
|
||||
cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \
|
||||
icl | *[/\\]icl | icl.exe | *[/\\]icl.exe )
|
||||
func_cl_wrapper "$@" # Doesn't return...
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as 'compile cc -o foo foo.c'.
|
||||
# So we strip '-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no '-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# '.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use '[/\\:.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'before-save-hook 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC0"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([picasso],[2.7.0],[https://github.com/fincs/picasso/issues])
|
||||
AC_INIT([picasso],[2.7.1],[https://github.com/devkitPro/picasso/issues])
|
||||
AC_CONFIG_SRCDIR([source/picasso_frontend.cpp])
|
||||
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
42
example/CMakeLists.txt
Normal file
42
example/CMakeLists.txt
Normal file
@ -0,0 +1,42 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
|
||||
project(linpicasso_sample)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-L${DEVKITPRO}/libctru/lib -L${DEVKITPRO}/picaGL/lib -L${DEVKITPRO}/portlibs/3ds/lib -specs=3dsx.specs -Wl,--gc-sections")
|
||||
|
||||
include_directories(${DEVKITPRO}/libctru/include ${DEVKITPRO}/picaGL/include ${DEVKITPRO}/portlibs/3ds/include)
|
||||
add_definitions("-D__3DS__")
|
||||
|
||||
set(APP_TITLE "${PROJECT_NAME}")
|
||||
set(APP_DESCRIPTION "Example of Lib Picasso")
|
||||
set(APP_AUTHOR "Tobi-D7, tobid7vx")
|
||||
|
||||
set(APP_ICON "/opt/devkitpro/libctru/default_icon.png")
|
||||
set(APP_ROMFS "${PROJECT_SOURCE_DIR}/romfs")
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
set(BASE_CTR ON CACHE BOOL "Enable 3ds")
|
||||
add_subdirectory(../ picasso)
|
||||
|
||||
add_executable(${PROJECT_NAME}.elf src/main.cpp)
|
||||
|
||||
target_include_directories(${PROJECT_NAME}.elf PRIVATE src ../include)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}.elf citro2d citro3d ctru m picasso)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.smdh
|
||||
COMMAND smdhtool --create "${APP_TITLE}" "${APP_DESCRIPTION}" "${APP_AUTHOR}" "${APP_ICON}" ${PROJECT_NAME}.smdh
|
||||
DEPENDS ${PROJECT_NAME}.elf
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.3dsx
|
||||
COMMAND 3dsxtool ${PROJECT_NAME}.elf ${PROJECT_NAME}.3dsx --romfs=${APP_ROMFS} --smdh=${PROJECT_NAME}.smdh
|
||||
DEPENDS ${PROJECT_NAME}.elf
|
||||
)
|
||||
|
||||
add_custom_target( 3ds ALL
|
||||
DEPENDS ${PROJECT_NAME}.smdh ${PROJECT_NAME}.3dsx
|
||||
)
|
36
example/romfs/vshader.pica
Normal file
36
example/romfs/vshader.pica
Normal file
@ -0,0 +1,36 @@
|
||||
; Example PICA200 vertex shader
|
||||
|
||||
; Uniforms
|
||||
.fvec projection[4]
|
||||
|
||||
; Constants
|
||||
.constf myconst(0.0, 1.0, -1.0, 0.1)
|
||||
.constf myconst2(0.3, 0.0, 0.0, 0.0)
|
||||
.alias zeros myconst.xxxx ; Vector full of zeros
|
||||
.alias ones myconst.yyyy ; Vector full of ones
|
||||
|
||||
; Outputs
|
||||
.out outpos position
|
||||
.out outclr color
|
||||
|
||||
; Inputs (defined as aliases for convenience)
|
||||
.alias inpos v0
|
||||
.alias inclr v1
|
||||
|
||||
.proc main
|
||||
; Force the w component of inpos to be 1.0
|
||||
mov r0.xyz, inpos
|
||||
mov r0.w, ones
|
||||
|
||||
; outpos = projectionMatrix * inpos
|
||||
dp4 outpos.x, projection[0], r0
|
||||
dp4 outpos.y, projection[1], r0
|
||||
dp4 outpos.z, projection[2], r0
|
||||
dp4 outpos.w, projection[3], r0
|
||||
|
||||
; outclr = inclr
|
||||
mov outclr, inclr
|
||||
|
||||
; We're finished
|
||||
end
|
||||
.end
|
174
example/src/main.cpp
Normal file
174
example/src/main.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
#include <3ds.h>
|
||||
#include <citro3d.h>
|
||||
|
||||
#include <pica.hpp>
|
||||
|
||||
static const char *const vertShader = R"text(
|
||||
; Example PICA200 vertex shader
|
||||
|
||||
; Uniforms
|
||||
.fvec projection[4]
|
||||
|
||||
; Constants
|
||||
.constf myconst(0.0, 1.0, -1.0, 0.1)
|
||||
.constf myconst2(0.3, 0.0, 0.0, 0.0)
|
||||
.alias zeros myconst.xxxx ; Vector full of zeros
|
||||
.alias ones myconst.yyyy ; Vector full of ones
|
||||
|
||||
; Outputs
|
||||
.out outpos position
|
||||
.out outclr color
|
||||
|
||||
; Inputs (defined as aliases for convenience)
|
||||
.alias inpos v0
|
||||
.alias inclr v1
|
||||
|
||||
.proc main
|
||||
; Force the w component of inpos to be 1.0
|
||||
mov r0.xyz, inpos
|
||||
mov r0.w, ones
|
||||
|
||||
; outpos = projectionMatrix * inpos
|
||||
dp4 outpos.x, projection[0], r0
|
||||
dp4 outpos.y, projection[1], r0
|
||||
dp4 outpos.z, projection[2], r0
|
||||
dp4 outpos.w, projection[3], r0
|
||||
|
||||
; outclr = inclr
|
||||
mov outclr, inclr
|
||||
|
||||
; We're finished
|
||||
end
|
||||
.end
|
||||
)text";
|
||||
|
||||
#define CLEAR_COLOR 0x68B0D8FF
|
||||
|
||||
#define DISPLAY_TRANSFER_FLAGS \
|
||||
(GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \
|
||||
GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \
|
||||
GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
|
||||
|
||||
typedef struct { float x, y, z; } vertex;
|
||||
|
||||
static const vertex vertex_list[] =
|
||||
{
|
||||
{ 200.0f, 200.0f, 0.5f },
|
||||
{ 100.0f, 40.0f, 0.5f },
|
||||
{ 300.0f, 40.0f, 0.5f },
|
||||
};
|
||||
|
||||
#define vertex_list_count (sizeof(vertex_list)/sizeof(vertex_list[0]))
|
||||
|
||||
static DVLB_s* vshader_dvlb;
|
||||
static shaderProgram_s program;
|
||||
static int uLoc_projection;
|
||||
static C3D_Mtx projection;
|
||||
|
||||
|
||||
static char* vshader_shbin;
|
||||
static int vshader_shbin_size;
|
||||
|
||||
static void* vbo_data;
|
||||
|
||||
static void sceneInit(void)
|
||||
{
|
||||
// Load the vertex shader, create a shader program and bind it
|
||||
vshader_dvlb = DVLB_ParseFile((u32*)vshader_shbin, vshader_shbin_size);
|
||||
shaderProgramInit(&program);
|
||||
shaderProgramSetVsh(&program, &vshader_dvlb->DVLE[0]);
|
||||
C3D_BindProgram(&program);
|
||||
|
||||
// Get the location of the uniforms
|
||||
uLoc_projection = shaderInstanceGetUniformLocation(program.vertexShader, "projection");
|
||||
|
||||
// Configure attributes for use with the vertex shader
|
||||
C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
|
||||
AttrInfo_Init(attrInfo);
|
||||
AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
|
||||
AttrInfo_AddFixed(attrInfo, 1); // v1=color
|
||||
|
||||
// Set the fixed attribute (color) to solid white
|
||||
C3D_FixedAttribSet(1, 1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
// Compute the projection matrix
|
||||
Mtx_OrthoTilt(&projection, 0.0, 400.0, 0.0, 240.0, 0.0, 1.0, true);
|
||||
|
||||
// Create the VBO (vertex buffer object)
|
||||
vbo_data = linearAlloc(sizeof(vertex_list));
|
||||
memcpy(vbo_data, vertex_list, sizeof(vertex_list));
|
||||
|
||||
// Configure buffers
|
||||
C3D_BufInfo* bufInfo = C3D_GetBufInfo();
|
||||
BufInfo_Init(bufInfo);
|
||||
BufInfo_Add(bufInfo, vbo_data, sizeof(vertex), 1, 0x0);
|
||||
|
||||
// Configure the first fragment shading substage to just pass through the vertex color
|
||||
// See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight
|
||||
C3D_TexEnv* env = C3D_GetTexEnv(0);
|
||||
C3D_TexEnvInit(env);
|
||||
C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, (GPU_TEVSRC)0, (GPU_TEVSRC)0);
|
||||
C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
|
||||
}
|
||||
|
||||
static void sceneRender(void)
|
||||
{
|
||||
// Update the uniforms
|
||||
C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uLoc_projection, &projection);
|
||||
|
||||
// Draw the VBO
|
||||
C3D_DrawArrays(GPU_TRIANGLES, 0, vertex_list_count);
|
||||
}
|
||||
|
||||
static void sceneExit(void)
|
||||
{
|
||||
// Free the VBO
|
||||
linearFree(vbo_data);
|
||||
|
||||
// Free the shader program
|
||||
shaderProgramFree(&program);
|
||||
DVLB_Free(vshader_dvlb);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialize graphics
|
||||
gfxInitDefault();
|
||||
romfsInit();
|
||||
C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
|
||||
//vshader_shbin = Pica::AssembleCode(vertShader, vshader_shbin_size);
|
||||
vshader_shbin = Pica::AssembleFile("romfs:/vshader.pica", vshader_shbin_size);
|
||||
|
||||
// Initialize the render target
|
||||
C3D_RenderTarget* target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8);
|
||||
C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
|
||||
|
||||
// Initialize the scene
|
||||
sceneInit();
|
||||
|
||||
// Main loop
|
||||
while (aptMainLoop())
|
||||
{
|
||||
hidScanInput();
|
||||
|
||||
// Respond to user input
|
||||
u32 kDown = hidKeysDown();
|
||||
if (kDown & KEY_START)
|
||||
break; // break in order to return to hbmenu
|
||||
|
||||
// Render the scene
|
||||
C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
|
||||
C3D_RenderTargetClear(target, C3D_CLEAR_ALL, CLEAR_COLOR, 0);
|
||||
C3D_FrameDrawOn(target);
|
||||
sceneRender();
|
||||
C3D_FrameEnd(0);
|
||||
}
|
||||
|
||||
// Deinitialize the scene
|
||||
sceneExit();
|
||||
|
||||
// Deinitialize graphics
|
||||
C3D_Fini();
|
||||
gfxExit();
|
||||
return 0;
|
||||
}
|
10
include/pica.hpp
Normal file
10
include/pica.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
namespace Pica
|
||||
{
|
||||
void InstallErrorCallback(void(*ErrorHandler)(const char* top, const char* message));
|
||||
char* AssembleCode(const char* vertex, int &res_size);
|
||||
char* AssembleFile(const char* file, int &res_size);
|
||||
}
|
@ -1,43 +1,44 @@
|
||||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include "types.h"
|
||||
#include "picasso/types.h"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
class FileClass
|
||||
{
|
||||
FILE* f;
|
||||
std::stringstream f;
|
||||
bool LittleEndian, own;
|
||||
int filePos;
|
||||
|
||||
size_t _RawRead(void* buffer, size_t size)
|
||||
{
|
||||
size_t x = fread(buffer, 1, size, f);
|
||||
filePos += x;
|
||||
return x;
|
||||
f.read((char*)buffer, size);
|
||||
filePos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t _RawWrite(const void* buffer, size_t size)
|
||||
{
|
||||
size_t x = fwrite(buffer, 1, size, f);
|
||||
filePos += x;
|
||||
return x;
|
||||
f.write((const char*)buffer, size);
|
||||
filePos += size;
|
||||
return size;
|
||||
}
|
||||
|
||||
public:
|
||||
FileClass(const char* file, const char* mode) : LittleEndian(true), own(true), filePos(0)
|
||||
{
|
||||
f = fopen(file, mode);
|
||||
//Do nothing
|
||||
}
|
||||
FileClass(FILE* inf) : f(inf), LittleEndian(true), own(false), filePos(0) { }
|
||||
~FileClass()
|
||||
{
|
||||
if (f && own) fclose(f);
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
void SetLittleEndian() { LittleEndian = true; }
|
||||
void SetBigEndian() { LittleEndian = false; }
|
||||
|
||||
FILE* get_ptr() { return f; }
|
||||
bool openerror() { return f == NULL; }
|
||||
std::stringstream* get_ptr() { return &f; }
|
||||
bool openerror() { return false; }
|
||||
|
||||
dword_t ReadDword()
|
||||
{
|
||||
@ -103,13 +104,11 @@ public:
|
||||
t.f = value;
|
||||
WriteWord(t.w);
|
||||
}
|
||||
|
||||
|
||||
bool ReadRaw(void* buffer, size_t size) { return _RawRead(buffer, size) == size; }
|
||||
bool WriteRaw(const void* buffer, size_t size) { return _RawWrite(buffer, size) == size; }
|
||||
|
||||
void Seek(int pos, int mode) { fseek(f, pos, mode); }
|
||||
int Tell() { return filePos /*ftell(f)*/; }
|
||||
void Flush() { fflush(f); }
|
||||
};
|
||||
|
||||
static inline char* StringFromFile(const char* filename)
|
||||
@ -129,4 +128,4 @@ static inline char* StringFromFile(const char* filename)
|
||||
buf[size] = 0;
|
||||
fclose(f);
|
||||
return buf;
|
||||
}
|
||||
}
|
@ -54,4 +54,4 @@ enum
|
||||
// Only the upper 3 bits are used for the following opcodes
|
||||
MAESTRO_MADI = 0x30,
|
||||
MAESTRO_MAD = 0x38,
|
||||
};
|
||||
};
|
@ -16,9 +16,9 @@
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
#include "FileClass.h"
|
||||
#include "picasso/FileClass.h"
|
||||
|
||||
#include "maestro_opcodes.h"
|
||||
#include "picasso/maestro_opcodes.h"
|
||||
|
||||
#if !defined(WIN32) && !defined(stricmp)
|
||||
#define stricmp strcasecmp
|
||||
@ -253,4 +253,4 @@ struct DVLEData
|
||||
nodvle(false), isGeoShader(false), isCompatGeoShader(false), isMerge(false),
|
||||
inputMask(0), outputMask(0), geoShaderType(0), geoShaderFixedStart(0), geoShaderVariableNum(0), geoShaderFixedNum(0),
|
||||
uniformCount(0), symbolSize(0), constantCount(0), outputUsedReg(0), outputCount(0) { }
|
||||
};
|
||||
};
|
@ -65,4 +65,4 @@ static inline uint64_t __builtin_bswap64(uint64_t x)
|
||||
#define le_hword(a) __builtin_bswap16(a)
|
||||
#else
|
||||
#error "What's the endianness of the platform you're targeting?"
|
||||
#endif
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
#include "picasso.h"
|
||||
#include "picasso/picasso.h"
|
||||
|
||||
//#define DEBUG
|
||||
#define BUF g_outputBuf
|
||||
@ -548,9 +548,13 @@ static int maskFromSwizzling(int sw, bool reverse = true)
|
||||
{
|
||||
sw >>= 1; // get rid of negation bit
|
||||
int out = 0;
|
||||
int prevbitid = 4;
|
||||
for (int i = 0; i < 4; i ++)
|
||||
{
|
||||
int bitid = (sw>>(i*2))&3;
|
||||
if (bitid > prevbitid)
|
||||
fprintf(stderr, "%s:%d: warning: arbitrary swizzling has no effect for destination mask\n", curFile, curLine);
|
||||
prevbitid=bitid;
|
||||
if (reverse) bitid = 3 - bitid;
|
||||
out |= BIT(bitid);
|
||||
}
|
||||
@ -716,7 +720,7 @@ static int parseReg(char* pos, int& outReg, int& outSw, int* idxType = NULL)
|
||||
char* idxRegName = trim_whitespace(offPos);
|
||||
offPos = trim_whitespace(plusPos);
|
||||
*idxType = convertIdxRegName(idxRegName);
|
||||
if (*idxType < 0)
|
||||
if (!*idxType)
|
||||
return throwError("invalid index register: %s\n", idxRegName);
|
||||
} while (0);
|
||||
|
||||
@ -1371,7 +1375,7 @@ DEF_DIRECTIVE(end)
|
||||
lastWasEnd = false;
|
||||
}
|
||||
|
||||
else if (elem.type == SE_PROC || elem.type == SE_FOR || (elem.type == SE_IF && BUF.size() > 0))
|
||||
else if ((elem.type == SE_PROC || elem.type == SE_FOR || elem.type == SE_IF) && BUF.size() > 0)
|
||||
{
|
||||
u32 p = BUF.size();
|
||||
u32 lastOpcode = BUF[p-1] >> 26;
|
||||
@ -1834,7 +1838,7 @@ DEF_DIRECTIVE(in)
|
||||
{
|
||||
ARG_TO_REG(inReg, inRegName);
|
||||
if (inReg < 0x00 || inReg >= 0x10)
|
||||
return throwError("invalid input register: %s\n", inReg);
|
||||
return throwError("invalid input register: %s\n", inRegName);
|
||||
oid = inReg;
|
||||
} else
|
||||
oid = dvle->findFreeInput();
|
||||
|
@ -206,7 +206,6 @@ int main(int argc, char* argv[])
|
||||
f.WriteWord(dvle->uniformCount); // size of uniform table
|
||||
curOff += dvle->uniformCount*8;
|
||||
f.WriteWord(curOff); // offset to symbol table
|
||||
u32 temp = f.Tell();
|
||||
f.WriteWord(dvle->symbolSize); // size of symbol table
|
||||
|
||||
// Sort uniforms by position
|
199
source/picasso_library.cpp
Normal file
199
source/picasso_library.cpp
Normal file
@ -0,0 +1,199 @@
|
||||
#include <pica.hpp>
|
||||
#include <picasso/picasso.h>
|
||||
// f24 has:
|
||||
// - 1 sign bit
|
||||
// - 7 exponent bits
|
||||
// - 16 mantissa bits
|
||||
uint32_t f32tof24(float f) {
|
||||
uint32_t i;
|
||||
memcpy(&i, &f, sizeof(f));
|
||||
|
||||
uint32_t mantissa = (i << 9) >> 9;
|
||||
int32_t exponent = (i << 1) >> 24;
|
||||
uint32_t sign = (i << 0) >> 31;
|
||||
|
||||
// Truncate mantissa
|
||||
mantissa >>= 7;
|
||||
|
||||
// Re-bias exponent
|
||||
exponent = exponent - 127 + 63;
|
||||
if (exponent < 0) {
|
||||
// Underflow: flush to zero
|
||||
return sign << 23;
|
||||
} else if (exponent > 0x7F) {
|
||||
// Overflow: saturate to infinity
|
||||
return (sign << 23) | (0x7F << 16);
|
||||
}
|
||||
|
||||
return (sign << 23) | (exponent << 16) | mantissa;
|
||||
}
|
||||
|
||||
void BasicHandler(const char *top, const char *message) {
|
||||
std::cout << top << std::endl << message << std::endl;
|
||||
}
|
||||
|
||||
static void (*EHND)(const char *top, const char *message) = BasicHandler;
|
||||
|
||||
namespace Pica {
|
||||
|
||||
void InstallErrorCallback(void (*ErrorHandler)(const char *top,
|
||||
const char *message)) {
|
||||
EHND = ErrorHandler;
|
||||
}
|
||||
|
||||
char *AssembleCode(const char *vertex, int &res_size) {
|
||||
int rc = 0;
|
||||
rc = AssembleString((char *)vertex, "llc_npi");
|
||||
if (rc) {
|
||||
EHND("Error when Assembling Code", vertex);
|
||||
}
|
||||
|
||||
rc = RelocateProduct();
|
||||
if (rc) {
|
||||
EHND("Error when Relocating Product", "0");
|
||||
}
|
||||
FileClass f("Dont Care", "wb");
|
||||
|
||||
u32 progSize = g_outputBuf.size();
|
||||
u32 dvlpSize = 10 * 4 + progSize * 4 + g_opdescCount * 8;
|
||||
|
||||
// Write DVLB header
|
||||
f.WriteWord(0x424C5644); // DVLB
|
||||
f.WriteWord(g_totalDvleCount); // Number of DVLEs
|
||||
|
||||
// Calculate and write DVLE offsets
|
||||
u32 curOff = 2 * 4 + g_totalDvleCount * 4 + dvlpSize;
|
||||
for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end();
|
||||
++dvle) {
|
||||
if (dvle->nodvle)
|
||||
continue;
|
||||
f.WriteWord(curOff);
|
||||
curOff += 16 * 4; // Header
|
||||
curOff += dvle->constantCount * 20;
|
||||
curOff += dvle->outputCount * 8;
|
||||
curOff += dvle->uniformCount * 8;
|
||||
curOff += dvle->symbolSize;
|
||||
curOff = (curOff + 3) & ~3; // Word alignment
|
||||
}
|
||||
|
||||
// Write DVLP header
|
||||
f.WriteWord(0x504C5644); // DVLP
|
||||
f.WriteWord(0); // version
|
||||
f.WriteWord(10 * 4); // offset to shader binary blob
|
||||
f.WriteWord(progSize); // size of shader binary blob
|
||||
f.WriteWord(10 * 4 + progSize * 4); // offset to opdesc table
|
||||
f.WriteWord(g_opdescCount); // number of opdescs
|
||||
f.WriteWord(dvlpSize); // offset to symtable (TODO)
|
||||
f.WriteWord(0); // ????
|
||||
f.WriteWord(0); // ????
|
||||
f.WriteWord(0); // ????
|
||||
|
||||
// Write program
|
||||
for (outputBufIter it = g_outputBuf.begin(); it != g_outputBuf.end(); ++it)
|
||||
f.WriteWord(*it);
|
||||
|
||||
// Write opdescs
|
||||
for (int i = 0; i < g_opdescCount; i++)
|
||||
f.WriteDword(g_opdescTable[i]);
|
||||
|
||||
// Write DVLEs
|
||||
for (dvleTableIter dvle = g_dvleTable.begin(); dvle != g_dvleTable.end();
|
||||
++dvle) {
|
||||
if (dvle->nodvle)
|
||||
continue;
|
||||
curOff = 16 * 4;
|
||||
|
||||
f.WriteWord(0x454C5644); // DVLE
|
||||
f.WriteHword(0x1002); // maybe version?
|
||||
f.WriteByte(dvle->isGeoShader ? 1 : 0); // Shader type
|
||||
f.WriteByte(dvle->isMerge ? 1 : 0);
|
||||
f.WriteWord(dvle->entryStart); // offset to main
|
||||
f.WriteWord(dvle->entryEnd); // offset to end of main
|
||||
f.WriteHword(dvle->inputMask);
|
||||
f.WriteHword(dvle->outputMask);
|
||||
f.WriteByte(dvle->geoShaderType);
|
||||
f.WriteByte(dvle->geoShaderFixedStart);
|
||||
f.WriteByte(dvle->geoShaderVariableNum);
|
||||
f.WriteByte(dvle->geoShaderFixedNum);
|
||||
f.WriteWord(curOff); // offset to constant table
|
||||
f.WriteWord(dvle->constantCount); // size of constant table
|
||||
curOff += dvle->constantCount * 5 * 4;
|
||||
f.WriteWord(curOff); // offset to label table (TODO)
|
||||
f.WriteWord(0); // size of label table (TODO)
|
||||
f.WriteWord(curOff); // offset to output table
|
||||
f.WriteWord(dvle->outputCount); // size of output table
|
||||
curOff += dvle->outputCount * 8;
|
||||
f.WriteWord(curOff); // offset to uniform table
|
||||
f.WriteWord(dvle->uniformCount); // size of uniform table
|
||||
curOff += dvle->uniformCount * 8;
|
||||
f.WriteWord(curOff); // offset to symbol table
|
||||
f.WriteWord(dvle->symbolSize); // size of symbol table
|
||||
|
||||
// Sort uniforms by position
|
||||
std::sort(dvle->uniformTable, dvle->uniformTable + dvle->uniformCount);
|
||||
|
||||
// Write constants
|
||||
for (int i = 0; i < dvle->constantCount; i++) {
|
||||
Constant &ct = dvle->constantTable[i];
|
||||
f.WriteHword(ct.type);
|
||||
if (ct.type == UTYPE_FVEC) {
|
||||
f.WriteHword(ct.regId - 0x20);
|
||||
for (int j = 0; j < 4; j++)
|
||||
f.WriteWord(f32tof24(ct.fparam[j]));
|
||||
} else if (ct.type == UTYPE_IVEC) {
|
||||
f.WriteHword(ct.regId - 0x80);
|
||||
for (int j = 0; j < 4; j++)
|
||||
f.WriteByte(ct.iparam[j]);
|
||||
} else if (ct.type == UTYPE_BOOL) {
|
||||
f.WriteHword(ct.regId - 0x88);
|
||||
f.WriteWord(ct.bparam ? 1 : 0);
|
||||
}
|
||||
if (ct.type != UTYPE_FVEC)
|
||||
for (int j = 0; j < 3; j++)
|
||||
f.WriteWord(0); // Padding
|
||||
}
|
||||
|
||||
// Write outputs
|
||||
for (int i = 0; i < dvle->outputCount; i++)
|
||||
f.WriteDword(dvle->outputTable[i]);
|
||||
|
||||
// Write uniforms
|
||||
size_t sp = 0;
|
||||
for (int i = 0; i < dvle->uniformCount; i++) {
|
||||
Uniform &u = dvle->uniformTable[i];
|
||||
size_t l = u.name.length() + 1;
|
||||
f.WriteWord(sp);
|
||||
sp += l;
|
||||
int pos = u.pos;
|
||||
if (pos >= 0x20)
|
||||
pos -= 0x10;
|
||||
f.WriteHword(pos);
|
||||
f.WriteHword(pos + u.size - 1);
|
||||
}
|
||||
|
||||
// Write symbols
|
||||
for (int i = 0; i < dvle->uniformCount; i++) {
|
||||
std::string u(dvle->uniformTable[i].name);
|
||||
std::replace(u.begin(), u.end(), '$', '.');
|
||||
size_t l = u.length() + 1;
|
||||
f.WriteRaw(u.c_str(), l);
|
||||
}
|
||||
|
||||
// Word alignment
|
||||
int pos = f.Tell();
|
||||
int pad = ((pos + 3) & ~3) - pos;
|
||||
for (int i = 0; i < pad; i++)
|
||||
f.WriteByte(0);
|
||||
}
|
||||
res_size = f.Tell();
|
||||
return (char *)f.get_ptr()->str().c_str();
|
||||
}
|
||||
|
||||
char *AssembleFile(const char *file, int &res_size) {
|
||||
char *sourceCode = StringFromFile(file);
|
||||
if (!sourceCode) {
|
||||
EHND("error:", "cannot open input file!\n");
|
||||
}
|
||||
return AssembleCode(sourceCode, res_size);
|
||||
}
|
||||
} // namespace Pica
|
Loading…
Reference in New Issue
Block a user