├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── Modules │ ├── FindGStreamer.cmake │ ├── FindNPA.cmake │ └── get-git-revision.cmake ├── include ├── Choice.hpp ├── Effect.hpp ├── GLTexture.hpp ├── Image.hpp ├── Movie.hpp ├── NSBContext.hpp ├── NSBInterpreter.hpp ├── Name.hpp ├── Object.hpp ├── Playable.hpp ├── ResourceMgr.hpp ├── Scrollbar.hpp ├── Text.hpp ├── TextParser.hpp ├── Texture.hpp ├── Variable.hpp ├── Window.hpp └── npengineversion.hpp.in └── src ├── Choice.cpp ├── GLTexture.cpp ├── Image.cpp ├── Movie.cpp ├── NSBContext.cpp ├── NSBDebugger.cpp ├── NSBInterpreter.cpp ├── Playable.cpp ├── ResourceMgr.cpp ├── Scrollbar.cpp ├── Text.cpp ├── Texture.cpp ├── Variable.cpp ├── Window.cpp ├── lexer.l └── parser.y /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | # add modules 4 | set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules") 5 | 6 | # set version 7 | set(LIBNPENGINE_VERSION_MAJOR "0") 8 | set(LIBNPENGINE_VERSION_MINOR "5") 9 | set(LIBNPENGINE_VERSION_PATCH "3") 10 | set(LIBNPENGINE_VERSION 11 | "${LIBNPENGINE_VERSION_MAJOR}.${LIBNPENGINE_VERSION_MINOR}.${LIBNPENGINE_VERSION_PATCH}" 12 | ) 13 | 14 | # append git revision if available 15 | include(get-git-revision) 16 | get_git_revision(LIBNPENGINE_VERSION_GIT) 17 | if(NOT "${LIBNPENGINE_VERSION_GIT}" STREQUAL "") 18 | set(LIBNPENGINE_VERSION "${LIBNPENGINE_VERSION}-${LIBNPENGINE_VERSION_GIT}") 19 | endif() 20 | 21 | message(STATUS "Configuring libnpengine version " ${LIBNPENGINE_VERSION}) 22 | 23 | # project name and language 24 | project (libnpengine CXX) 25 | 26 | set(CMAKE_BUILD_TYPE Debug) 27 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -O2 -Wall") 28 | 29 | # include version number in header 30 | configure_file(${PROJECT_SOURCE_DIR}/include/npengineversion.hpp.in 31 | ${PROJECT_SOURCE_DIR}/include/npengineversion.hpp) 32 | 33 | find_package(NPA REQUIRED) 34 | find_package(GLEW REQUIRED) 35 | find_package(JPEG REQUIRED) 36 | find_package(GStreamer REQUIRED) 37 | find_package(FLEX REQUIRED) 38 | find_package(BISON REQUIRED) 39 | find_package(PNG REQUIRED) 40 | find_package(Threads REQUIRED) 41 | include(FindPkgConfig) 42 | 43 | PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2) 44 | PKG_SEARCH_MODULE(libpng REQUIRED libpng) 45 | PKG_SEARCH_MODULE(PANGOCAIRO REQUIRED pangocairo) 46 | 47 | string(REPLACE "." ";" VERSION_LIST ${FLEX_VERSION}) 48 | list(GET VERSION_LIST 0 FLEX_VERSION_MAJOR) 49 | list(GET VERSION_LIST 1 FLEX_VERSION_MINOR) 50 | list(GET VERSION_LIST 2 FLEX_VERSION_PATCH) 51 | add_definitions(-DFLEX_VERSION_MAJOR=${FLEX_VERSION_MAJOR}) 52 | add_definitions(-DFLEX_VERSION_MINOR=${FLEX_VERSION_MINOR}) 53 | add_definitions(-DFLEX_VERSION_PATCH=${FLEX_VERSION_PATCH}) 54 | 55 | include_directories( 56 | ${PANGOCAIRO_INCLUDE_DIRS} 57 | ${SDL2_INCLUDE_DIRS} 58 | ${NPA_INCLUDE_DIR} 59 | ${GSTREAMER_INCLUDE_DIRS} 60 | ${GSTREAMER_VIDEO_INCLUDE_DIRS} 61 | ${CMAKE_SOURCE_DIR}/include 62 | ) 63 | 64 | link_directories( 65 | ) 66 | 67 | flex_target(lexer ${CMAKE_SOURCE_DIR}/src/lexer.l ${CMAKE_SOURCE_DIR}/src/Lexer.cpp) 68 | bison_target(parser ${CMAKE_SOURCE_DIR}/src/parser.y ${CMAKE_SOURCE_DIR}/src/Parser.cpp) 69 | 70 | add_library(npengine SHARED 71 | src/Window.cpp 72 | src/NSBInterpreter.cpp 73 | src/ResourceMgr.cpp 74 | src/Texture.cpp 75 | src/Variable.cpp 76 | src/NSBContext.cpp 77 | src/GLTexture.cpp 78 | src/Playable.cpp 79 | src/Movie.cpp 80 | src/Choice.cpp 81 | src/Text.cpp 82 | src/Parser.cpp 83 | src/Lexer.cpp 84 | src/Image.cpp 85 | src/NSBDebugger.cpp 86 | src/Scrollbar.cpp 87 | ) 88 | 89 | target_link_libraries(npengine 90 | ${CMAKE_THREAD_LIBS_INIT} 91 | ${SDL2_LIBRARIES} 92 | ${NPA_LIBRARY} 93 | ${GSTREAMER_LIBRARIES} 94 | ${GSTREAMER_APP_LIBRARIES} 95 | ${GSTREAMER_VIDEO_LIBRARIES} 96 | ${PANGOCAIRO_LIBRARIES} 97 | ${JPEG_LIBRARY} 98 | ${GLEW_LIBRARY} 99 | ${PNG_LIBRARIES} 100 | -lGL) 101 | 102 | # install headers and library 103 | install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ 104 | DESTINATION include/libnpengine 105 | FILES_MATCHING PATTERN "*.hpp") 106 | install(TARGETS npengine DESTINATION lib) 107 | 108 | # create packages 109 | set(CPACK_GENERATOR "TBZ2") 110 | set(CPACK_PACKAGE_VERSION ${LIBNPENGINE_VERSION}) 111 | include(CPack) 112 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libnpengine 2 | =========== 3 | 4 | libnpengine is a free implementation of Nitroplus visual novel game engine. 5 | It can currently run [Steins;Gate][2] and [few other games][1]. For more information, visit the project [website][3]. 6 | 7 | If you need help getting this to compile and run or simply want to chat, join #FGRE @ irc.freenode.net 8 | 9 | [1]: https://github.com/FGRE/chaos-head 10 | [2]: https://github.com/FGRE/steins-gate-new 11 | [3]: http://dev.pulsir.eu/krofna/ -------------------------------------------------------------------------------- /cmake/Modules/FindGStreamer.cmake: -------------------------------------------------------------------------------- 1 | # - Try to find GStreamer and its plugins 2 | # Once done, this will define 3 | # 4 | # GSTREAMER_FOUND - system has GStreamer 5 | # GSTREAMER_INCLUDE_DIRS - the GStreamer include directories 6 | # GSTREAMER_LIBRARIES - link these to use GStreamer 7 | # 8 | # Additionally, gstreamer-base is always looked for and required, and 9 | # the following related variables are defined: 10 | # 11 | # GSTREAMER_BASE_INCLUDE_DIRS - gstreamer-base's include directory 12 | # GSTREAMER_BASE_LIBRARIES - link to these to use gstreamer-base 13 | # 14 | # Optionally, the COMPONENTS keyword can be passed to find_package() 15 | # and GStreamer plugins can be looked for. Currently, the following 16 | # plugins can be searched, and they define the following variables if 17 | # found: 18 | # 19 | # gstreamer-app: GSTREAMER_APP_INCLUDE_DIRS and GSTREAMER_APP_LIBRARIES 20 | # gstreamer-audio: GSTREAMER_AUDIO_INCLUDE_DIRS and GSTREAMER_AUDIO_LIBRARIES 21 | # gstreamer-fft: GSTREAMER_FFT_INCLUDE_DIRS and GSTREAMER_FFT_LIBRARIES 22 | # gstreamer-gl: GSTREAMER_GL_INCLUDE_DIRS and GSTREAMER_GL_LIBRARIES 23 | # gstreamer-mpegts: GSTREAMER_MPEGTS_INCLUDE_DIRS and GSTREAMER_MPEGTS_LIBRARIES 24 | # gstreamer-pbutils: GSTREAMER_PBUTILS_INCLUDE_DIRS and GSTREAMER_PBUTILS_LIBRARIES 25 | # gstreamer-tag: GSTREAMER_TAG_INCLUDE_DIRS and GSTREAMER_TAG_LIBRARIES 26 | # gstreamer-video: GSTREAMER_VIDEO_INCLUDE_DIRS and GSTREAMER_VIDEO_LIBRARIES 27 | # 28 | # Copyright (C) 2012 Raphael Kubo da Costa 29 | # 30 | # Redistribution and use in source and binary forms, with or without 31 | # modification, are permitted provided that the following conditions 32 | # are met: 33 | # 1. Redistributions of source code must retain the above copyright 34 | # notice, this list of conditions and the following disclaimer. 35 | # 2. Redistributions in binary form must reproduce the above copyright 36 | # notice, this list of conditions and the following disclaimer in the 37 | # documentation and/or other materials provided with the distribution. 38 | # 39 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS 40 | # IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 41 | # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 | # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS 43 | # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 44 | # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 45 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 46 | # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 47 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48 | # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 49 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50 | 51 | find_package(PkgConfig) 52 | 53 | # Helper macro to find a GStreamer plugin (or GStreamer itself) 54 | # _component_prefix is prepended to the _INCLUDE_DIRS and _LIBRARIES variables (eg. "GSTREAMER_AUDIO") 55 | # _pkgconfig_name is the component's pkg-config name (eg. "gstreamer-1.0", or "gstreamer-video-1.0"). 56 | # _library is the component's library name (eg. "gstreamer-1.0" or "gstvideo-1.0") 57 | macro(FIND_GSTREAMER_COMPONENT _component_prefix _pkgconfig_name _library) 58 | 59 | string(REGEX MATCH "(.*)>=(.*)" _dummy "${_pkgconfig_name}") 60 | if ("${CMAKE_MATCH_2}" STREQUAL "" AND (NOT ${GStreamer_FIND_VERSION} STREQUAL "")) 61 | pkg_check_modules(PC_${_component_prefix} "${_pkgconfig_name} >= ${GStreamer_FIND_VERSION}") 62 | else () 63 | pkg_check_modules(PC_${_component_prefix} ${_pkgconfig_name}) 64 | endif () 65 | set(${_component_prefix}_INCLUDE_DIRS ${PC_${_component_prefix}_INCLUDE_DIRS}) 66 | 67 | find_library(${_component_prefix}_LIBRARIES 68 | NAMES ${_library} 69 | HINTS ${PC_${_component_prefix}_LIBRARY_DIRS} ${PC_${_component_prefix}_LIBDIR} 70 | ) 71 | endmacro() 72 | 73 | # ------------------------ 74 | # 1. Find GStreamer itself 75 | # ------------------------ 76 | 77 | # 1.1. Find headers and libraries 78 | FIND_GSTREAMER_COMPONENT(GSTREAMER gstreamer-1.0 gstreamer-1.0) 79 | FIND_GSTREAMER_COMPONENT(GSTREAMER_BASE gstreamer-base-1.0 gstbase-1.0) 80 | 81 | # ------------------------- 82 | # 2. Find GStreamer plugins 83 | # ------------------------- 84 | 85 | FIND_GSTREAMER_COMPONENT(GSTREAMER_APP gstreamer-app-1.0 gstapp-1.0) 86 | FIND_GSTREAMER_COMPONENT(GSTREAMER_AUDIO gstreamer-audio-1.0 gstaudio-1.0) 87 | FIND_GSTREAMER_COMPONENT(GSTREAMER_FFT gstreamer-fft-1.0 gstfft-1.0) 88 | FIND_GSTREAMER_COMPONENT(GSTREAMER_GL gstreamer-gl-1.0>=1.5.0 gstgl-1.0) 89 | FIND_GSTREAMER_COMPONENT(GSTREAMER_MPEGTS gstreamer-mpegts-1.0>=1.4.0 gstmpegts-1.0) 90 | FIND_GSTREAMER_COMPONENT(GSTREAMER_PBUTILS gstreamer-pbutils-1.0 gstpbutils-1.0) 91 | FIND_GSTREAMER_COMPONENT(GSTREAMER_TAG gstreamer-tag-1.0 gsttag-1.0) 92 | FIND_GSTREAMER_COMPONENT(GSTREAMER_VIDEO gstreamer-video-1.0 gstvideo-1.0) 93 | 94 | # ------------------------------------------------ 95 | # 3. Process the COMPONENTS passed to FIND_PACKAGE 96 | # ------------------------------------------------ 97 | set(_GSTREAMER_REQUIRED_VARS GSTREAMER_INCLUDE_DIRS GSTREAMER_LIBRARIES GSTREAMER_VERSION GSTREAMER_BASE_INCLUDE_DIRS GSTREAMER_BASE_LIBRARIES) 98 | 99 | foreach (_component ${GStreamer_FIND_COMPONENTS}) 100 | set(_gst_component "GSTREAMER_${_component}") 101 | string(TOUPPER ${_gst_component} _UPPER_NAME) 102 | 103 | list(APPEND _GSTREAMER_REQUIRED_VARS ${_UPPER_NAME}_INCLUDE_DIRS ${_UPPER_NAME}_LIBRARIES) 104 | endforeach () 105 | 106 | include(FindPackageHandleStandardArgs) 107 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(GStreamer REQUIRED_VARS _GSTREAMER_REQUIRED_VARS 108 | VERSION_VAR GSTREAMER_VERSION) 109 | 110 | mark_as_advanced( 111 | GSTREAMER_APP_INCLUDE_DIRS 112 | GSTREAMER_APP_LIBRARIES 113 | GSTREAMER_AUDIO_INCLUDE_DIRS 114 | GSTREAMER_AUDIO_LIBRARIES 115 | GSTREAMER_BASE_INCLUDE_DIRS 116 | GSTREAMER_BASE_LIBRARIES 117 | GSTREAMER_FFT_INCLUDE_DIRS 118 | GSTREAMER_FFT_LIBRARIES 119 | GSTREAMER_GL_INCLUDE_DIRS 120 | GSTREAMER_GL_LIBRARIES 121 | GSTREAMER_INCLUDE_DIRS 122 | GSTREAMER_LIBRARIES 123 | GSTREAMER_MPEGTS_INCLUDE_DIRS 124 | GSTREAMER_MPEGTS_LIBRARIES 125 | GSTREAMER_PBUTILS_INCLUDE_DIRS 126 | GSTREAMER_PBUTILS_LIBRARIES 127 | GSTREAMER_TAG_INCLUDE_DIRS 128 | GSTREAMER_TAG_LIBRARIES 129 | GSTREAMER_VIDEO_INCLUDE_DIRS 130 | GSTREAMER_VIDEO_LIBRARIES 131 | ) 132 | -------------------------------------------------------------------------------- /cmake/Modules/FindNPA.cmake: -------------------------------------------------------------------------------- 1 | # find our libnpa 2 | # when successful, defines: 3 | # - NPA_LIBRARY 4 | # - NPA_FOUND 5 | # - NPA_INCLUDE_DIR 6 | # - NPA_LIBRARY_DIR 7 | 8 | # define the list of search paths for headers and libraries 9 | set(FIND_NPA_PATHS 10 | ${NPA_ROOT} 11 | $ENV{NPA_ROOT} 12 | /usr/local 13 | /usr 14 | /opt/local 15 | /opt 16 | ${CMAKE_SOURCE_DIR}/../libnpa # for krofna's build setup 17 | ) 18 | 19 | # find include directory 20 | find_path(NPA_INCLUDE_DIR npaversion.hpp 21 | PATH_SUFFIXES include include/libnpa 22 | PATHS ${FIND_NPA_PATHS} 23 | ) 24 | 25 | # TODO: check version number 26 | 27 | # find library 28 | find_library(NPA_LIBRARY 29 | NAMES npa 30 | PATH_SUFFIXES lib64 lib 31 | PATHS ${FIND_NPA_PATHS} 32 | ) 33 | 34 | # set result 35 | if (NPA_LIBRARY) 36 | set(NPA_FOUND TRUE) 37 | # directory 38 | get_filename_component(_dir "${NPA_LIBRARY}" PATH) 39 | set(NPA_LIBRARY_DIR "${_dir}" CACHE PATH "NPA library directory" FORCE) 40 | else() 41 | set(NPA_FOUND FALSE) 42 | endif() 43 | 44 | # errors 45 | if(NOT NPA_FOUND) 46 | set(FIND_NPA_ERROR "Could NOT find NPA") 47 | endif() 48 | if (NOT NPA_FOUND) 49 | if(NPA_FIND_REQUIRED) 50 | message(FATAL_ERROR ${FIND_NPA_ERROR}) 51 | elseif(NOT NPA_FIND_QUIETLY) 52 | message("${FIND_NPA_ERROR}") 53 | endif() 54 | endif() 55 | 56 | # success 57 | if(NPA_FOUND) 58 | message(STATUS "Found NPA in ${NPA_INCLUDE_DIR}") 59 | endif() 60 | -------------------------------------------------------------------------------- /cmake/Modules/get-git-revision.cmake: -------------------------------------------------------------------------------- 1 | 2 | # this function returns the git hash of the current checkout, if the 'git' 3 | # command is available, it is a git checkout and it is not a tagged release. 4 | function(get_git_revision _hashvar) 5 | # got git? 6 | if(NOT GIT_FOUND) 7 | find_package(Git QUIET) 8 | endif() 9 | if(GIT_FOUND) 10 | # TODO: look for source directory (for out-of-source builds)? 11 | 12 | # check, if we have a tagged release 13 | execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags --exact-match 14 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 15 | RESULT_VARIABLE EXIT_CODE 16 | OUTPUT_QUIET 17 | ERROR_QUIET 18 | ) 19 | # it failed => not a tagged revision 20 | if(NOT ${EXIT_CODE} EQUAL 0) 21 | execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short=10 HEAD 22 | WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" 23 | RESULT_VARIABLE EXIT_CODE 24 | OUTPUT_VARIABLE GIT_REV 25 | ERROR_QUIET 26 | OUTPUT_STRIP_TRAILING_WHITESPACE 27 | ) 28 | if(${EXIT_CODE} EQUAL 0) 29 | # all good, set hash 30 | set(${_hashvar} "${GIT_REV}" PARENT_SCOPE) 31 | return() 32 | endif() 33 | endif() 34 | endif() 35 | # no git available or any other error above, set to empty string 36 | set(${_hashvar} "" PARENT_SCOPE) 37 | endfunction() 38 | -------------------------------------------------------------------------------- /include/Choice.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef CHOICE_HPP 19 | #define CHOICE_HPP 20 | 21 | #include "Texture.hpp" 22 | #include "Name.hpp" 23 | #include 24 | 25 | class Choice : public Name 26 | { 27 | enum 28 | { 29 | FOCUS_UP, 30 | FOCUS_DOWN, 31 | FOCUS_RIGHT, 32 | FOCUS_LEFT 33 | }; 34 | 35 | public: 36 | Choice(); 37 | 38 | bool IsSelected(const SDL_Event& Event); 39 | void SetNextFocus(Choice* pNext, const string& Key); 40 | void Reset() { ButtonUp = false; } 41 | 42 | private: 43 | void Cursor(int x, int y, bool& Flag); 44 | void Wheel(int x, int y); 45 | void Arrow(SDL_Keycode sym); 46 | void ChangeFocus(int Index); 47 | int KeyToIndex(const string& Key); 48 | 49 | bool MouseOver; 50 | bool ButtonDown; 51 | bool ButtonUp; 52 | Choice* pNextFocus[4]; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/Effect.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef EFFECT_HPP 19 | #define EFFECT_HPP 20 | 21 | #include 22 | #include 23 | #include "Texture.hpp" 24 | #include "nsbconstants.hpp" 25 | 26 | class Effect 27 | { 28 | public: 29 | Effect() : Tempo(-1), Program(0) { } 30 | ~Effect() { glDeleteObjectARB(Program); } 31 | 32 | protected: 33 | float ApplyTempo(float Progress) 34 | { 35 | switch (Tempo) 36 | { 37 | case Nsb::AXL_1: 38 | return pow(Progress, 2); 39 | case Nsb::AXL_2: 40 | return pow(Progress, 3); 41 | case Nsb::AXL_3: 42 | return pow(Progress, 4); 43 | case Nsb::DXL_1: 44 | return 1.0f - pow(1.0f - Progress, 2); 45 | case Nsb::DXL_2: 46 | return 1.0f - pow(1.0f - Progress, 3); 47 | case Nsb::DXL_3: 48 | return 1.0f - pow(1.0f - Progress, 4); 49 | case Nsb::AXL_AUTO: 50 | return 1.0f - cos(Progress * M_PI * 0.5f); 51 | case Nsb::DXL_AUTO: 52 | return sin(Progress * M_PI * 0.5f); 53 | case Nsb::AXL_DXL: 54 | return 0.5f * (1.0f - cos(Progress * M_PI)); 55 | case Nsb::DXL_AXL: 56 | return acos(1.0f - Progress * 2.0f) / M_PI; 57 | } 58 | return Progress; 59 | } 60 | 61 | int32_t Lerp(int32_t Old, int32_t New, float Progress) 62 | { 63 | if (New > Old) 64 | return Old + (New - Old) * ApplyTempo(Progress); 65 | else 66 | return Old - (Old - New) * ApplyTempo(Progress); 67 | } 68 | 69 | void CompileShader(const char* String) 70 | { 71 | if (!GLEW_ARB_fragment_shader) 72 | return; 73 | 74 | GLuint Shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); 75 | glShaderSourceARB(Shader, 1, &String, NULL); 76 | glCompileShaderARB(Shader); 77 | 78 | Program = glCreateProgramObjectARB(); 79 | glAttachObjectARB(Program, Shader); 80 | 81 | glLinkProgramARB(Program); 82 | glDeleteObjectARB(Shader); 83 | } 84 | 85 | int32_t Tempo; 86 | GLuint Program; 87 | }; 88 | 89 | class Tone : public Effect 90 | { 91 | const string MonochromeShader = \ 92 | "uniform sampler2D Texture;" 93 | "void main()" 94 | "{" 95 | " vec4 Pixel = texture2D(Texture, gl_TexCoord[0].xy);" 96 | " gl_FragColor = vec4(vec3(Pixel.r + Pixel.g + Pixel.b) / 3.0, Pixel.a);" 97 | "}"; 98 | const string NegaPosiShader = \ 99 | "uniform sampler2D Texture;" 100 | "void main()" 101 | "{" 102 | " vec4 Pixel = texture2D(Texture, gl_TexCoord[0].xy);" 103 | " gl_FragColor = vec4(vec3(1.0) - Pixel.rgb, Pixel.a);" 104 | "}"; 105 | const string KitanoBlueShader = \ 106 | "uniform sampler2D Texture;" 107 | "void main()" 108 | "{" 109 | " vec4 Pixel = texture2D(Texture, gl_TexCoord[0].xy);" 110 | " float Intensity = Pixel.r * (27.0 / 255.0) + Pixel.g * (150.0 / 255.0) + Pixel.b * (76.0 / 255.0);" 111 | " vec4 Color = vec4(vec3(Intensity), Pixel.a);" 112 | " Color.gb = clamp(Color.gb + vec2(20.0 / 255.0, 80.0 / 255.0), vec2(0.0, 0.0), vec2(1.0, 1.0));" 113 | " gl_FragColor = Color;" 114 | "}"; 115 | const string SepiaShader = \ 116 | "uniform sampler2D Texture;" 117 | "void main()" 118 | "{" 119 | " vec4 Pixel = texture2D(Texture, gl_TexCoord[0].xy);" 120 | " float Intensity = Pixel.r * (27.0 / 255.0) + Pixel.g * (150.0 / 255.0) + Pixel.b * (76.0 / 255.0);" 121 | " vec4 Color = vec4(vec3(Intensity), Pixel.a);" 122 | " Color.rg = clamp(Color.rg + vec2(30.0 / 255.0, 30.0 / 255.0), vec2(0.0, 0.0), vec2(1.0, 1.0));" 123 | " gl_FragColor = Color;" 124 | "}"; 125 | public: 126 | Tone(int32_t Tone) 127 | { 128 | switch (Tone) 129 | { 130 | case Nsb::NEGA_POSI: 131 | CompileShader(NegaPosiShader.c_str()); 132 | break; 133 | case Nsb::MONOCHROME: 134 | CompileShader(MonochromeShader.c_str()); 135 | break; 136 | case Nsb::SEPIA: 137 | CompileShader(SepiaShader.c_str()); 138 | break; 139 | case Nsb::KITANO_BLUE: 140 | CompileShader(KitanoBlueShader.c_str()); 141 | break; 142 | } 143 | } 144 | 145 | void OnDraw() 146 | { 147 | if (!Program) 148 | return; 149 | 150 | glUseProgramObjectARB(Program); 151 | glUniform1iARB(glGetUniformLocationARB(Program, "Texture"), 0); 152 | } 153 | }; 154 | 155 | class LerpEffect : public Effect 156 | { 157 | public: 158 | LerpEffect() { } 159 | LerpEffect(int32_t StartX, int32_t StartY) : EndX(StartX), EndY(StartY) { } 160 | 161 | void Reset(int32_t StartX, int32_t EndX, int32_t StartY, int32_t EndY, int32_t Time, int32_t Tempo) 162 | { 163 | this->StartX = StartX; 164 | this->StartY = StartY; 165 | this->EndX = EndX; 166 | this->EndY = EndY; 167 | this->Time = Time; 168 | this->ElapsedTime = 0; 169 | this->Tempo = Tempo; 170 | } 171 | 172 | void Reset(int32_t EndX, int32_t EndY, int32_t Time, int32_t Tempo) 173 | { 174 | Reset(this->EndX, EndX, this->EndY, EndY, Time, Tempo); 175 | } 176 | 177 | float GetProgress() 178 | { 179 | if (ElapsedTime >= Time) 180 | return 1.0f; 181 | return float(ElapsedTime) / float(Time); 182 | } 183 | 184 | void Update(int32_t diff, int32_t& x, int32_t& y) 185 | { 186 | ElapsedTime += diff; 187 | x = Lerp(StartX, EndX, GetProgress()); 188 | y = Lerp(StartY, EndY, GetProgress()); 189 | } 190 | 191 | int32_t StartX, StartY; 192 | int32_t EndX, EndY; 193 | int32_t ElapsedTime; 194 | int32_t Time; 195 | }; 196 | 197 | class RotateEffect : public LerpEffect 198 | { 199 | public: 200 | RotateEffect(int32_t EndA, int32_t Time, int32_t Tempo) : LerpEffect(0, 0) 201 | { 202 | Reset(EndA, 0, Time, Tempo); 203 | } 204 | 205 | void OnDraw(Texture* pTexture, int32_t diff) 206 | { 207 | int32_t ax, ay; 208 | Update(diff, ax, ay); 209 | pTexture->SetAngle(ax); 210 | } 211 | }; 212 | 213 | class MoveEffect : public LerpEffect 214 | { 215 | public: 216 | MoveEffect(int32_t EndX, int32_t EndY, int32_t Time, int32_t Tempo) : LerpEffect(0, 0) 217 | { 218 | Reset(EndX, EndY, Time, Tempo); 219 | } 220 | 221 | void OnDraw(Texture* pTexture, int32_t diff) 222 | { 223 | int32_t x, y; 224 | Update(diff, x, y); 225 | pTexture->SetPosition(x, y); 226 | } 227 | }; 228 | 229 | class ZoomEffect : public LerpEffect 230 | { 231 | public: 232 | ZoomEffect(int32_t EndX, int32_t EndY, int32_t Time, int32_t Tempo) : LerpEffect(1000, 1000) 233 | { 234 | Reset(EndX, EndY, Time, Tempo); 235 | } 236 | 237 | void OnDraw(Texture* pTexture, int32_t diff) 238 | { 239 | int32_t x, y; 240 | Update(diff, x, y); 241 | pTexture->SetScale(x, y); 242 | } 243 | }; 244 | 245 | class FadeEffect : public LerpEffect 246 | { 247 | const string MaskShader = \ 248 | "uniform sampler2D Texture;" 249 | "uniform float Alpha;" 250 | "void main()" 251 | "{" 252 | " vec4 Pixel = texture2D(Texture, gl_TexCoord[0].xy);" 253 | " Pixel.a *= Alpha;" 254 | " gl_FragColor = Pixel;" 255 | "}"; 256 | public: 257 | FadeEffect() 258 | { 259 | } 260 | 261 | FadeEffect(int32_t EndOpacity, int32_t Time, int32_t Tempo) : LerpEffect(1000, 0) 262 | { 263 | CompileShader(MaskShader.c_str()); 264 | Reset(EndOpacity, 0, Time, Tempo); 265 | } 266 | 267 | void OnDraw(int32_t diff) 268 | { 269 | int32_t x, y; 270 | Update(diff, x, y); 271 | 272 | if (!Program) 273 | return; 274 | 275 | glUseProgramObjectARB(Program); 276 | glUniform1fARB(glGetUniformLocationARB(Program, "Alpha"), x * 0.001f); 277 | glUniform1iARB(glGetUniformLocationARB(Program, "Texture"), 0); 278 | } 279 | }; 280 | 281 | class MaskEffect : public FadeEffect, GLTexture 282 | { 283 | const string MaskShader = \ 284 | "uniform sampler2D Texture;" 285 | "uniform sampler2D Mask;" 286 | "uniform float Alpha;" 287 | "uniform float Boundary;" 288 | "void main()" 289 | "{" 290 | " vec4 Pixel = texture2D(Texture, gl_TexCoord[0].xy);" 291 | " vec4 MaskPixel = texture2D(Mask, gl_TexCoord[0].xy);" 292 | " if (MaskPixel.r - Alpha <= 0.0f) Pixel.a = 1.0f;" 293 | " else if (MaskPixel.r - Alpha - Boundary <= 0.0f) Pixel.a = -(MaskPixel.r - Alpha - Boundary) / Boundary;" 294 | " else Pixel.a = 0.0f;" 295 | " gl_FragColor = Pixel;" 296 | "}"; 297 | public: 298 | MaskEffect(const string& Filename, int32_t StartOpacity, int32_t EndOpacity, int32_t Time, int32_t Boundary, int32_t Tempo) 299 | { 300 | CompileShader(MaskShader.c_str()); 301 | Reset(Filename, StartOpacity, EndOpacity, Time, Boundary, Tempo); 302 | } 303 | 304 | void Reset(const string& Filename, int32_t StartOpacity, int32_t EndOpacity, int32_t Time, int32_t Boundary, int32_t Tempo) 305 | { 306 | CreateFromFile(Filename, true); 307 | LerpEffect::Reset(StartOpacity, EndOpacity, 0, 0, Time, Tempo); 308 | 309 | if (!Program) 310 | return; 311 | 312 | glUseProgramObjectARB(Program); 313 | glActiveTextureARB(GL_TEXTURE1_ARB); 314 | glBindTexture(GL_TEXTURE_2D, GLTextureID); 315 | glUniform1iARB(glGetUniformLocationARB(Program, "Mask"), 1); 316 | glActiveTextureARB(GL_TEXTURE0_ARB); 317 | glUniform1fARB(glGetUniformLocationARB(Program, "Boundary"), Boundary * 0.001f); 318 | } 319 | }; 320 | 321 | class BlurEffect : public Effect, GLTexture 322 | { 323 | const string BlurShader = \ 324 | "uniform float Sigma;" 325 | "uniform sampler2D Texture;" 326 | "uniform vec2 Pass;" 327 | "uniform float BlurSize;" 328 | "const float NumSamples = 11.0f;" 329 | "const float PI = 3.14159265f;" 330 | "void main()" 331 | "{" 332 | " vec3 Gaussian = vec3(1.0f / (sqrt(2.0f * PI) * Sigma), exp(-0.5f / (Sigma * Sigma)), 0.0f);" 333 | " Gaussian.z = Gaussian.y * Gaussian.y;" 334 | " vec4 Average = texture2D(Texture, gl_TexCoord[0].xy) * Gaussian.x;" 335 | " float CoeffSum = Gaussian.x;" 336 | " Gaussian.xy *= Gaussian.yz;" 337 | " for (float i = 1.0f; i <= NumSamples; ++i)" 338 | " {" 339 | " Average += texture2D(Texture, gl_TexCoord[0].xy + i * BlurSize * Pass) * Gaussian.x;" 340 | " Average += texture2D(Texture, gl_TexCoord[0].xy - i * BlurSize * Pass) * Gaussian.x;" 341 | " CoeffSum += 2.0f * Gaussian.x;" 342 | " Gaussian.xy *= Gaussian.yz;" 343 | " }" 344 | " gl_FragColor = Average / CoeffSum;" 345 | "}"; 346 | public: 347 | BlurEffect() : Framebuffer(GL_INVALID_VALUE) 348 | { 349 | } 350 | 351 | ~BlurEffect() 352 | { 353 | glDeleteFramebuffers(1, &Framebuffer); 354 | } 355 | 356 | bool Create(int Width, int Height, float Sigma) 357 | { 358 | CompileShader(BlurShader.c_str()); 359 | 360 | if (!Program) 361 | return false; 362 | 363 | glUseProgramObjectARB(Program); 364 | glUniform1fARB(glGetUniformLocationARB(Program, "Sigma"), Sigma); 365 | glUniform1iARB(glGetUniformLocationARB(Program, "Texture"), 0); 366 | 367 | glGenFramebuffers(1, &Framebuffer); 368 | glBindFramebuffer(GL_FRAMEBUFFER, Framebuffer); 369 | CreateEmpty(Width, Height); 370 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, GLTextureID, 0); 371 | 372 | if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) 373 | { 374 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 375 | return false; 376 | } 377 | 378 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 379 | return true; 380 | } 381 | 382 | void OnDraw(GLTexture* pTexture, float* xa, float* ya, float Width, float Height) 383 | { 384 | glUseProgramObjectARB(Program); 385 | 386 | // Switch to FBO 387 | glBindFramebuffer(GL_FRAMEBUFFER, Framebuffer); 388 | glPushAttrib(GL_VIEWPORT_BIT); 389 | glViewport(0, 0, this->Width, this->Height); 390 | 391 | // Flip texture 392 | glMatrixMode(GL_PROJECTION); 393 | glPushMatrix(); 394 | glLoadIdentity(); 395 | glOrtho(0, this->Width, 0, this->Height, -1, 1); 396 | 397 | // First pass to texture 398 | glUniform1fARB(glGetUniformLocationARB(Program, "BlurSize"), 1.0f / this->Width); 399 | glUniform2fARB(glGetUniformLocationARB(Program, "Pass"), 1.0f, 0.0f); 400 | pTexture->Draw(0, 0, this->Width, this->Height); 401 | 402 | // Switch to window 403 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 404 | glPopAttrib(); 405 | glPopMatrix(); 406 | 407 | // Second pass to window 408 | glUniform1fARB(glGetUniformLocationARB(Program, "BlurSize"), 1.0f / Height); 409 | glUniform2fARB(glGetUniformLocationARB(Program, "Pass"), 0.0f, 1.0f); 410 | Draw(xa, ya); 411 | } 412 | 413 | GLuint Framebuffer; 414 | }; 415 | 416 | #endif 417 | -------------------------------------------------------------------------------- /include/GLTexture.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef GL_TEXTURE_HPP 19 | #define GL_TEXTURE_HPP 20 | 21 | #include 22 | #include "Object.hpp" 23 | 24 | class Image; 25 | class Window; 26 | class Texture; 27 | class GLTexture : virtual public Object 28 | { 29 | friend class Texture; 30 | public: 31 | GLTexture(); 32 | virtual ~GLTexture(); 33 | 34 | void Draw(int X, int Y, const string& Filename); 35 | void Draw(float X, float Y, float Width, float Height); 36 | void Draw(const float* xa, const float* ya); 37 | 38 | void CreateFromScreen(Window* pWindow); 39 | void CreateFromImage(Image* pImage); 40 | void CreateFromImageClip(Image* pImage, int ClipX, int ClipY, int ClipWidth, int ClipHeight); 41 | void CreateFromColor(int Width, int Height, uint32_t Color); 42 | void CreateFromFile(const string& Filename, bool Mask = false); 43 | void CreateFromFileClip(const string& Filename, int ClipX, int ClipY, int ClipWidth, int ClipHeight); 44 | void CreateEmpty(int Width, int Height); 45 | void Create(uint8_t* Pixels, GLenum Format, int W, int H); 46 | 47 | protected: 48 | void SetSmoothing(bool Set); 49 | 50 | int Width, Height; 51 | GLuint GLTextureID; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /include/Image.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef IMAGE_HPP 19 | #define IMAGE_HPP 20 | 21 | #include 22 | #include "Object.hpp" 23 | 24 | class Image : public Object 25 | { 26 | public: 27 | Image(); 28 | ~Image(); 29 | 30 | GLenum GetFormat() const { return Format; } 31 | int GetWidth() const { return Width; } 32 | int GetHeight() const { return Height; } 33 | uint8_t* GetPixels() const { return pPixels; } 34 | void LoadColor(int Width, int Height, uint32_t Color); 35 | void LoadImage(const string& Filename, bool Mask = false); 36 | void LoadScreen(Window* pWindow); 37 | 38 | private: 39 | uint8_t* LoadPNG(uint8_t* pMem, uint32_t Size, uint8_t Format); 40 | uint8_t* LoadJPEG(uint8_t* pMem, uint32_t Size); 41 | 42 | GLenum Format; 43 | int Width, Height; 44 | uint8_t* pPixels; 45 | }; 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/Movie.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2013-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef MOVIE_HPP 19 | #define MOVIE_HPP 20 | 21 | #include "Playable.hpp" 22 | #include "Texture.hpp" 23 | #include 24 | 25 | class Movie : public Playable, public Texture 26 | { 27 | friend void LinkPad(GstElement* DecodeBin, GstPad* SourcePad, gpointer Data); 28 | public: 29 | Movie(const string& FileName, Window* pWindow, int32_t Priority, bool Alpha, bool Audio); 30 | ~Movie(); 31 | 32 | virtual void Request(int32_t State) { Playable::Request(State); } 33 | void Draw(uint32_t Diff); 34 | private: 35 | void InitVideo(Window* pWindow); 36 | void UpdateSample(); 37 | 38 | bool Alpha; 39 | GstElement* VideoBin; 40 | GstAppSink* Appsink; 41 | }; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/NSBContext.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef NSB_CONTEXT_HPP 19 | #define NSB_CONTEXT_HPP 20 | 21 | #include "Object.hpp" 22 | #include 23 | #include 24 | 25 | class ScriptFile; 26 | class Line; 27 | class Text; 28 | class NSBContext : public Object 29 | { 30 | struct StackFrame 31 | { 32 | ScriptFile* pScript; 33 | uint32_t SourceLine; 34 | }; 35 | public: 36 | NSBContext(const string& Name); 37 | ~NSBContext(); 38 | 39 | bool Call(ScriptFile* pScript, const string& Symbol); 40 | void Jump(const string& Symbol); 41 | void Break(); 42 | const string& GetParam(uint32_t Index); 43 | int GetNumParams(); 44 | const string& GetScriptName(); 45 | ScriptFile* GetScript(); 46 | Line* GetLine(); 47 | uint32_t GetLineNumber(); 48 | uint32_t GetMagic(); 49 | uint32_t Advance(); 50 | void Rewind(); 51 | void Return(); 52 | void PushBreak(); 53 | void PopBreak(); 54 | void WaitText(Text* pText, int32_t Time); 55 | void WaitAction(Object* pObject, int32_t Time); 56 | void WaitKey(int32_t Time); 57 | void Wait(int32_t Time, bool Interrupt = false); 58 | void Wake(); 59 | void TryWake(); 60 | void OnClick(); 61 | bool IsStarving(); 62 | bool IsSleeping(); 63 | bool IsActive(); 64 | void Start(); 65 | void Request(int32_t State); 66 | const string& GetName(); 67 | void WriteTrace(ostream& Stream); 68 | void Update(uint32_t Diff); 69 | 70 | private: 71 | StackFrame* GetFrame(); 72 | 73 | Text* pText; 74 | Object* pObject; 75 | const string Name; 76 | uint64_t WaitTime; 77 | uint64_t Elapsed; 78 | bool WaitInterrupt; 79 | bool Active; 80 | stack CallStack; 81 | stack BreakStack; 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/NSBInterpreter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef NSB_INTERPRETER_HPP 19 | #define NSB_INTERPRETER_HPP 20 | 21 | #include "Variable.hpp" 22 | #include "Choice.hpp" 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | using namespace std; 29 | 30 | class Stack 31 | { 32 | public: 33 | Stack() : ReadIndex(0), WriteIndex(0) 34 | { 35 | } 36 | 37 | void Push(Variable* pVar) 38 | { 39 | if (WriteIndex == Params.size()) 40 | Params.push_back(pVar); 41 | else 42 | Params[WriteIndex] = pVar; 43 | WriteIndex++; 44 | } 45 | 46 | Variable* Top() 47 | { 48 | return Params[ReadIndex]; 49 | } 50 | 51 | Variable* TTop() 52 | { 53 | return Params[ReadIndex + 1]; 54 | } 55 | 56 | Variable* Pop() 57 | { 58 | return Params[ReadIndex++]; 59 | } 60 | 61 | void Begin(size_t Size) 62 | { 63 | WriteIndex -= Size; 64 | ReadIndex = WriteIndex; 65 | } 66 | 67 | void Reset() 68 | { 69 | ReadIndex = WriteIndex = 0; 70 | Params.clear(); 71 | } 72 | 73 | private: 74 | vector Params; 75 | size_t ReadIndex; 76 | size_t WriteIndex; 77 | }; 78 | 79 | typedef function PosFunc; 80 | struct NSBPosition 81 | { 82 | NSBPosition() : Func(nullptr) { } 83 | PosFunc Func; 84 | bool Relative; 85 | int32_t operator()(int32_t xy, int32_t Old = 0) { return Relative ? Old + Func(xy) : Func(xy); } 86 | }; 87 | 88 | class Line; 89 | class Window; 90 | class Texture; 91 | class Playable; 92 | class Scrollbar; 93 | class NSBContext; 94 | class NSBInterpreter 95 | { 96 | struct NSBFunction 97 | { 98 | typedef void (NSBInterpreter::*BuiltinFunc)(); 99 | NSBFunction(BuiltinFunc Func, uint8_t NumParams) : Func(Func), NumParams(NumParams) { } 100 | BuiltinFunc Func; 101 | uint8_t NumParams; 102 | }; 103 | struct NSBShortcut 104 | { 105 | SDL_Keycode Key; 106 | const string Script; 107 | }; 108 | public: 109 | NSBInterpreter(Window* pWindow); 110 | virtual ~NSBInterpreter(); 111 | 112 | void ExecuteLocalScript(const string& Filename); 113 | void ExecuteScript(const string& Filename); 114 | void ExecuteScriptThread(const string& Filename); 115 | void StartDebugger(); 116 | 117 | void PushEvent(const SDL_Event& Event); 118 | virtual void HandleEvent(const SDL_Event& Event); 119 | void Update(uint32_t Diff); 120 | void Run(int NumCommands); 121 | void RunCommand(); 122 | 123 | protected: 124 | void FunctionDeclaration(); 125 | void CallFunction(); 126 | void CallScene(); 127 | void CallChapter(); 128 | void CmpLogicalAnd(); 129 | void CmpLogicalOr(); 130 | void CmpGreater(); 131 | void CmpLess(); 132 | void CmpGE(); 133 | void CmpLE(); 134 | void CmpEqual(); 135 | void CmpNE(); 136 | void NotExpression(); 137 | void AddExpression(); 138 | void SubExpression(); 139 | void MulExpression(); 140 | void DivExpression(); 141 | void ModExpression(); 142 | void Increment(); 143 | void Decrement(); 144 | void Literal(); 145 | void Assign(); 146 | void Get(); 147 | void ScopeBegin(); 148 | void ScopeEnd(); 149 | void Return(); 150 | void If(); 151 | void While(); 152 | void WhileEnd(); 153 | void Select(); 154 | void SelectEnd(); 155 | void SelectBreakEnd(); 156 | void Break(); 157 | void Jump(); 158 | void AddAssign(); 159 | void SubAssign(); 160 | void ModAssign(); 161 | void WriteFile(); 162 | void ReadFile(); 163 | void CreateTexture(); 164 | void ImageHorizon(); 165 | void ImageVertical(); 166 | void Time(); 167 | void StrStr(); 168 | void Exit(); 169 | void CursorPosition(); 170 | void MoveCursor(); 171 | void Position(); 172 | void Wait(); 173 | void WaitKey(); 174 | void NegaExpression(); 175 | void System(); 176 | void String(); 177 | void VariableValue(); 178 | void CreateProcess(); 179 | void Count(); 180 | void Array(); 181 | void SubScript(); 182 | void AssocArray(); 183 | void ModuleFileName(); 184 | void Request(); 185 | void SetVertex(); 186 | void Zoom(); 187 | void Move(); 188 | void SetShade(); 189 | void DrawToTexture(); 190 | void CreateRenderTexture(); 191 | void DrawTransition(); 192 | void CreateColor(); 193 | void LoadImage(); 194 | void Fade(); 195 | void Delete(); 196 | void ClearParams(); 197 | void SetLoop(); 198 | void SetVolume(); 199 | void SetLoopPoint(); 200 | void CreateSound(); 201 | void RemainTime(); 202 | void CreateMovie(); 203 | void DurationTime(); 204 | void SetFrequency(); 205 | void SetPan(); 206 | void SetAlias(); 207 | void CreateName(); 208 | void CreateWindow(); 209 | void CreateChoice(); 210 | void Case(); 211 | void CaseEnd(); 212 | void SetNextFocus(); 213 | void PassageTime(); 214 | void ParseText(); 215 | void LoadText(); 216 | void WaitText(); 217 | void LockVideo(); 218 | void Save(); 219 | void DeleteSaveFile(); 220 | void Conquest(); 221 | void ClearScore(); 222 | void ClearBacklog(); 223 | void SetFont(); 224 | void SetShortcut(); 225 | void CreateClipTexture(); 226 | void ExistSave(); 227 | void WaitAction(); 228 | void Load(); 229 | void SetBacklog(); 230 | void CreateText(); 231 | void AtExpression(); 232 | void Random(); 233 | void CreateEffect(); 234 | void SetTone(); 235 | void DateTime(); 236 | void Shake(); 237 | void MoviePlay(); 238 | void SetStream(); 239 | void WaitPlay(); 240 | void WaitFade(); 241 | void SoundAmplitude(); 242 | void Rotate(); 243 | void Message(); 244 | void Integer(); 245 | void CreateScrollbar(); 246 | void SetScrollbarValue(); 247 | void SetScrollbarWheelArea(); 248 | void ScrollbarValue(); 249 | void CreateStencil(); 250 | void CreateMask(); 251 | 252 | float PopFloat(); 253 | int32_t PopInt(); 254 | string PopString(); 255 | NSBPosition PopPos(); 256 | NSBPosition PopRelative(); 257 | uint32_t PopColor(); 258 | int32_t PopRequest(); 259 | int32_t PopTone(); 260 | int32_t PopEffect(); 261 | int32_t PopShade(); 262 | int32_t PopTempo(); 263 | bool PopBool(); 264 | string PopSave(); 265 | Variable* PopVar(); 266 | Texture* PopTexture(); 267 | GLTexture* PopGLTexture(); 268 | Playable* PopPlayable(); 269 | Scrollbar* PopScrollbar(); 270 | 271 | void PushFloat(float Float); 272 | void PushInt(int32_t Int); 273 | void PushString(const string& Str); 274 | void PushVar(Variable* pVar); 275 | void Assign_(int Index); 276 | 277 | void IntUnaryOp(function Func); 278 | void IntBinaryOp(function Func); 279 | void FloatBinaryOp(function Func); 280 | void BoolBinaryOp(function Func); 281 | 282 | void SetInt(const string& Name, int32_t Val); 283 | void SetString(const string& Name, const string& Val); 284 | void SetVar(const string& Name, Variable* pVar); 285 | virtual void OnVariableChanged(const string& Name); 286 | int32_t GetInt(const string& Name); 287 | string GetString(const string& Name); 288 | bool GetBool(const string& Name); 289 | bool ToBool(Variable* pVar); 290 | Variable* GetVar(const string& Name); 291 | Object* GetObject(const string& Name); 292 | template T* Get(const string& Name); 293 | void CallFunction_(NSBContext* pThread, const string& Symbol); 294 | void CallScriptSymbol(const string& Prefix); 295 | void CallScript(const string& Filename, const string& Symbol); 296 | void CallScriptThread(const string& Filename, const string& Symbol); 297 | void Call(uint16_t Magic); 298 | bool SelectEvent(); 299 | void AddThread(NSBContext* pThread); 300 | void RemoveThread(NSBContext* pThread); 301 | void ProcessKey(int Key, const string& Val); 302 | void ProcessButton(int button, const string& Val); 303 | 304 | void DebuggerMain(); 305 | void Inspect(int32_t n); 306 | void DbgBreak(bool Break); 307 | void DebuggerTick(); 308 | void PrintVariable(Variable* pVar); 309 | void SetBreakpoint(const string& Script, int32_t LineNumber); 310 | thread* pDebuggerThread; 311 | bool LogCalls; 312 | bool DbgStepping; 313 | bool RunInterpreter; 314 | list> Breakpoints; 315 | 316 | bool SkipHack; 317 | bool ThreadsModified; 318 | SDL_Event Event; 319 | queue Events; 320 | Window* pWindow; 321 | NSBContext* pContext; 322 | vector Builtins; 323 | Stack Params; 324 | vector Shortcuts; 325 | vector Scripts; 326 | list Threads; 327 | Holder VariableHolder; 328 | ObjectHolder_t ObjectHolder; 329 | }; 330 | 331 | template T* NSBInterpreter::Get(const string& Name) 332 | { 333 | return dynamic_cast(GetObject(Name)); 334 | } 335 | 336 | #endif 337 | -------------------------------------------------------------------------------- /include/Name.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef NAME_HPP 19 | #define NAME_HPP 20 | 21 | #include "Object.hpp" 22 | 23 | struct Name : Object 24 | { 25 | }; 26 | 27 | struct Window_t : Name 28 | { 29 | int32_t Priority, X, Y, Width, Height; 30 | }; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /include/Object.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef OBJECT_HPP 19 | #define OBJECT_HPP 20 | 21 | #include "ResourceMgr.hpp" 22 | #include "nsbconstants.hpp" 23 | #include 24 | 25 | struct Object; 26 | class ObjectHolder_t : private Holder 27 | { 28 | public: 29 | virtual ~ObjectHolder_t() 30 | { 31 | } 32 | 33 | Object* Read(const string& Handle) 34 | { 35 | string Leftover = Handle; 36 | string ObjHandle = ExtractObjHandle(Leftover); 37 | if (Leftover.empty()) 38 | return Holder::Read(ObjHandle); 39 | return GetHolder(ObjHandle)->Read(Leftover); 40 | } 41 | 42 | void Write(const string& Handle, Object* pObject) 43 | { 44 | string Leftover = Handle; 45 | string ObjHandle = ExtractObjHandle(Leftover); 46 | if (Leftover.empty()) 47 | Holder::Write(ObjHandle, pObject); 48 | else 49 | GetHolder(ObjHandle)->Write(Leftover, pObject); 50 | } 51 | 52 | void Delete(const string& Handle) 53 | { 54 | Write(Handle, nullptr); 55 | } 56 | 57 | template 58 | void Execute(const string& Handle, F Func) 59 | { 60 | string Leftover = Handle; 61 | string ObjHandle = ExtractObjHandle(Leftover); 62 | if (ObjHandle.back() == '*') 63 | ObjHandle.front() == '@' ? WildcardAlias(Leftover, ObjHandle, Func) : WildcardCache(Leftover, ObjHandle, Func); 64 | else 65 | Leftover.empty() ? CallSafe(ReadPointer(ObjHandle), Func) : ExecuteSafe(ObjHandle, Leftover, Func); 66 | } 67 | 68 | void WriteAlias(const string& Handle, const string& Alias) 69 | { 70 | Aliases[Alias] = Handle; 71 | } 72 | 73 | private: 74 | template 75 | void CallSafe(Object** ppObject, F Func) 76 | { 77 | if (ppObject) 78 | Func(ppObject); 79 | } 80 | 81 | template 82 | void ExecuteSafe(const string& HolderHandle, const string& Handle, F Func) 83 | { 84 | if (ObjectHolder_t* pHolder = GetHolder(HolderHandle)) 85 | pHolder->Execute(Handle, Func); 86 | } 87 | 88 | template 89 | void WildcardAlias(const string& Leftover, const string& ObjHandle, F Func) 90 | { 91 | std::regex Regex(Regexify(ObjHandle.substr(1))); 92 | for (auto i = Aliases.begin(); i != Aliases.end(); ++i) 93 | if (std::regex_match(i->first, Regex)) 94 | Leftover.empty() ? Execute(i->second, Func) : ExecuteSafe(i->second, Leftover, Func); 95 | } 96 | 97 | template 98 | void WildcardCache(const string& Leftover, const string& ObjHandle, F Func) 99 | { 100 | std::regex Regex(Regexify(ObjHandle)); 101 | for (auto i = Cache.begin(); i != Cache.end(); ++i) 102 | if (std::regex_match(i->first, Regex)) 103 | Leftover.empty() ? CallSafe(&i->second, Func) : ExecuteSafe(i->first, Leftover, Func); 104 | } 105 | 106 | string Regexify(const string& Wildcard) 107 | { 108 | return string("^" + Wildcard.substr(0, Wildcard.size() - 1) + ".*"); 109 | } 110 | 111 | string ExtractObjHandle(string& Handle) 112 | { 113 | // Name 114 | string ObjHandle; 115 | size_t Index = Handle.find('/'); 116 | if (Index != string::npos) 117 | { 118 | ObjHandle = Handle.substr(0, Index); 119 | Handle = Handle.substr(Index + 1); 120 | } 121 | else 122 | { 123 | ObjHandle = Handle; 124 | Handle.clear(); 125 | } 126 | // Alias 127 | if (ObjHandle.front() == '@' && ObjHandle.back() != '*') 128 | { 129 | Handle = Aliases[ObjHandle.substr(1)] + "/" + Handle; 130 | ObjHandle = ExtractObjHandle(Handle); 131 | } 132 | return ObjHandle; 133 | } 134 | 135 | ObjectHolder_t* GetHolder(const string& Handle) 136 | { 137 | return (ObjectHolder_t*)(Holder::Read(Handle)); 138 | } 139 | 140 | map Aliases; 141 | }; 142 | 143 | class Window; 144 | struct Object : ObjectHolder_t 145 | { 146 | Object() : Lock(false) 147 | { 148 | } 149 | virtual ~Object() 150 | { 151 | } 152 | virtual void Request(int32_t State) 153 | { 154 | switch (State) 155 | { 156 | case Nsb::LOCK: Lock = true; break; 157 | case Nsb::UN_LOCK: Lock = false; break; 158 | } 159 | } 160 | virtual bool Action() 161 | { 162 | return false; 163 | } 164 | bool Lock; 165 | static Window* pWindow; 166 | }; 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /include/Playable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2013-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef PLAYABLE_HPP 19 | #define PLAYABLE_HPP 20 | 21 | #include 22 | #include 23 | #include "Object.hpp" 24 | #include "ResourceMgr.hpp" 25 | 26 | struct AppSrc 27 | { 28 | AppSrc(Resource& Res); 29 | GstAppSrc* Appsrc; 30 | gsize Offset; 31 | Resource File; 32 | }; 33 | 34 | class Playable : virtual public Object 35 | { 36 | friend void LinkPad(GstElement* DecodeBin, GstPad* SourcePad, gpointer Data); 37 | public: 38 | Playable(const string& FileName); 39 | Playable(Resource Res); 40 | virtual ~Playable(); 41 | 42 | void SetVolume(int32_t Time, int32_t Volume, int32_t Tempo); 43 | void SetFrequency(int32_t Time, int32_t Frequency, int32_t Tempo); 44 | void SetPan(int32_t Time, int32_t Pan, int32_t Tempo); 45 | void SetLoopPoint(int32_t Begin, int32_t End); 46 | void SetLoop(bool Loop); 47 | void Stop(); 48 | void Play(); 49 | int32_t RemainTime(); 50 | int32_t DurationTime(); 51 | int32_t PassageTime(); 52 | void OnEOS(); 53 | void Request(int32_t State); 54 | virtual bool Action(); 55 | 56 | std::unique_ptr Appsrc; 57 | protected: 58 | void InitAudio(); 59 | void InitPipeline(GstElement* Source); 60 | 61 | GstElement* Pipeline; 62 | bool Playing; 63 | private: 64 | bool Loop; 65 | GstElement* AudioBin; 66 | GstElement* VolumeFilter; 67 | gint64 Begin, End; 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /include/ResourceMgr.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2013-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef RESOURCE_MGR_HPP 19 | #define RESOURCE_MGR_HPP 20 | 21 | #include 22 | #include 23 | #include 24 | #include "inpafile.hpp" 25 | using namespace std; 26 | 27 | class ScriptFile; 28 | 29 | template 30 | struct Holder 31 | { 32 | virtual ~Holder() 33 | { 34 | for (auto& i : Cache) 35 | delete i.second; 36 | } 37 | 38 | T** ReadPointer(const string& Path) 39 | { 40 | auto iter = Cache.find(Path); 41 | if (iter != Cache.end()) 42 | return &iter->second; 43 | return nullptr; 44 | } 45 | 46 | T* Read(const string& Path) 47 | { 48 | if (T** ppT = ReadPointer(Path)) 49 | return *ppT; 50 | return nullptr; 51 | } 52 | 53 | void Write(const string& Path, T* Data) 54 | { 55 | if (T** ppT = ReadPointer(Path)) 56 | { 57 | delete *ppT; 58 | *ppT = Data; 59 | } 60 | else 61 | Cache[Path] = Data; 62 | } 63 | 64 | map Cache; 65 | }; 66 | 67 | class Resource 68 | { 69 | public: 70 | Resource(INpaFile* pArchive, INpaFile::NpaIterator File) : pArchive(pArchive), File(File) { } 71 | 72 | bool IsValid() { return pArchive != nullptr; } 73 | uint32_t GetSize() { return pArchive->GetFileSize(File); } 74 | char* ReadData(uint32_t Offset, uint32_t Size); 75 | 76 | private: 77 | INpaFile* pArchive; 78 | INpaFile::NpaIterator File; 79 | }; 80 | 81 | class ResourceMgr 82 | { 83 | public: 84 | ResourceMgr(); 85 | virtual ~ResourceMgr(); 86 | 87 | virtual Resource GetResource(string Path); 88 | virtual char* Read(string Path, uint32_t& Size); 89 | ScriptFile* GetScriptFile(const string& Path); 90 | ScriptFile* ResolveSymbol(const string& Symbol, uint32_t& CodeLine); 91 | 92 | protected: 93 | virtual ScriptFile* ReadScriptFile(const string& Path) = 0; 94 | Holder CacheHolder; 95 | vector Archives; 96 | }; 97 | 98 | extern ResourceMgr* sResourceMgr; 99 | 100 | #endif 101 | -------------------------------------------------------------------------------- /include/Scrollbar.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef SCROLLBAR_HPP 19 | #define SCROLLBAR_HPP 20 | 21 | #include "Object.hpp" 22 | 23 | class Texture; 24 | class Scrollbar : public Object 25 | { 26 | public: 27 | Scrollbar(Texture* pTexture, int32_t X1, int32_t Y1, int32_t X2, int32_t Y2, int32_t Min, int32_t Max, string Type, string Callback); 28 | ~Scrollbar(); 29 | 30 | void SetWheelArea(int32_t X, int32_t Y, int32_t Width, int32_t Height); 31 | void SetValue(int32_t NewValue); 32 | int32_t GetValue(); 33 | private: 34 | Texture* pTexture; 35 | int32_t WX, WY, WWidth, WHeight; 36 | int32_t X1, Y1, X2, Y2; 37 | int32_t Min, Max; 38 | int32_t Value; 39 | string Type, Callback; 40 | }; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /include/Text.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef TEXT_HPP 19 | #define TEXT_HPP 20 | 21 | #include "Texture.hpp" 22 | #include "TextParser.hpp" 23 | 24 | class Playable; 25 | class Text : public Texture, private TextParser::Text 26 | { 27 | public: 28 | Text(); 29 | ~Text(); 30 | 31 | void CreateFromXML(const string& XML); 32 | void CreateFromString(const string& String); 33 | 34 | void SetCharacterSize(uint32_t Size); 35 | void SetColor(uint32_t Color); 36 | void SetWrap(int32_t Width); 37 | bool Advance(); 38 | 39 | void Request(int32_t State); 40 | 41 | static string dFont; 42 | static int32_t dSize; 43 | static uint32_t dInColor; 44 | static uint32_t dOutColor; 45 | static int32_t dWeight; 46 | static string dAlign; 47 | private: 48 | void SetString(const string& String); 49 | 50 | size_t Index, LayoutWidth; 51 | uint32_t Size, Color; 52 | }; 53 | 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/TextParser.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef TEXT_PARSER_HPP 19 | #define TEXT_PARSER_HPP 20 | 21 | #include 22 | #include 23 | using namespace std; 24 | 25 | namespace TextParser 26 | { 27 | 28 | class Line; 29 | class StringSegment; 30 | typedef vector LinesList; 31 | typedef vector String; 32 | typedef vector ArgumentList; 33 | typedef ArgumentList Voice; 34 | 35 | enum VoiceAttr 36 | { 37 | ATTR_NAME, 38 | ATTR_CLASS, 39 | ATTR_SRC, 40 | ATTR_MODE 41 | }; 42 | 43 | struct StringSegment 44 | { 45 | string Segment, Ruby; 46 | string InColor, OutColor; 47 | }; 48 | 49 | struct Line 50 | { 51 | String StringSegs; 52 | Voice VoiceAttrs; 53 | }; 54 | 55 | struct Text 56 | { 57 | LinesList Lines; 58 | }; 59 | 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /include/Texture.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef TEXTURE_HPP 19 | #define TEXTURE_HPP 20 | 21 | #include "Object.hpp" 22 | #include "GLTexture.hpp" 23 | 24 | class MoveEffect; 25 | class ZoomEffect; 26 | class FadeEffect; 27 | class MaskEffect; 28 | class BlurEffect; 29 | class RotateEffect; 30 | class Tone; 31 | class Texture : public GLTexture 32 | { 33 | public: 34 | Texture(); 35 | virtual ~Texture(); 36 | 37 | void CreateFromGLTexture(GLTexture* pTexture); 38 | 39 | void Request(int32_t State); 40 | void SetPosition(int X, int Y); 41 | void SetAngle(int Angle); 42 | void SetScale(int XScale, int YScale); 43 | void SetVertex(int X, int Y); 44 | void UpdateEffects(uint32_t Diff); 45 | virtual void Draw(uint32_t Diff); 46 | void SetPriority(int Priority); 47 | void Move(int X, int Y, int32_t Time = 0, int32_t Tempo = -1); 48 | void Zoom(int32_t Time, int X, int Y, int32_t Tempo); 49 | void Fade(int32_t Time, int Opacity, int32_t Tempo = -1); 50 | void DrawTransition(int32_t Time, int32_t Start, int32_t End, int32_t Boundary, int32_t Tempo, const string& Filename); 51 | void SetShade(int32_t Shade); 52 | void SetTone(int32_t Tone); 53 | void Rotate(int32_t Angle, int32_t Time, int32_t Tempo); 54 | void Shake(int32_t XWidth, int32_t YWidth, int32_t Time); 55 | 56 | int GetXScale() { return XScale; } 57 | int GetYScale() { return YScale; } 58 | int GetAngle() { return Angle; } 59 | int GetPriority() { return Priority; } 60 | int GetWidth() { return Width; } 61 | int GetHeight() { return Height; } 62 | int GetX() { return X; } 63 | int GetY() { return Y; } 64 | int GetOX() { return OX; } 65 | int GetOY() { return OY; } 66 | int32_t GetMX(); 67 | int32_t GetMY(); 68 | int32_t RemainFade(); 69 | 70 | private: 71 | MoveEffect* pMove; 72 | ZoomEffect* pZoom; 73 | FadeEffect* pFade; 74 | MaskEffect* pMask; 75 | BlurEffect* pBlur; 76 | RotateEffect* pRotate; 77 | Tone* pTone; 78 | int Priority; 79 | int X, Y; 80 | int OX, OY; 81 | int Angle; 82 | int XScale, YScale; 83 | int XShake, YShake, ShakeTime; 84 | bool ShakeTick; 85 | }; 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /include/Variable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef VARIABLE_HPP 19 | #define VARIABLE_HPP 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | using namespace std; 26 | 27 | class Variable 28 | { 29 | protected: 30 | enum 31 | { 32 | NSB_NULL = 0, 33 | NSB_INT = 1, 34 | NSB_FLOAT = 2, 35 | NSB_STRING = 3, 36 | NSB_BOOL = 4 37 | } Tag; 38 | 39 | struct 40 | { 41 | int32_t Int; 42 | float Float; 43 | string Str; 44 | bool Bool; 45 | } Val; 46 | 47 | Variable(); 48 | 49 | void Initialize(); 50 | void Initialize(Variable* pVar); 51 | 52 | public: 53 | virtual ~Variable(); 54 | 55 | static Variable* MakeNull(const string& Name); 56 | static Variable* MakeFloat(float Float); 57 | static Variable* MakeInt(int32_t Int); 58 | static Variable* MakeString(const string& Str); 59 | static Variable* MakeCopy(Variable* pVar, const string& Name); 60 | 61 | int GetTag(); 62 | float ToFloat(); 63 | int32_t ToInt(); 64 | string ToString(); 65 | bool IsFloat(); 66 | bool IsInt(); 67 | bool IsString(); 68 | bool IsNull(); 69 | void Set(Variable* pVar); 70 | void Set(float Float); 71 | void Set(int32_t Int); 72 | void Set(const string& Str); 73 | Variable* IntUnaryOp(function Func); 74 | 75 | static Variable* Add(Variable* pFirst, Variable* pSecond); 76 | static void Destroy(Variable* pVar); 77 | 78 | bool Literal; 79 | bool Relative; 80 | map Assoc; 81 | string Name; 82 | }; 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /include/Window.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #ifndef WINDOW_HPP 19 | #define WINDOW_HPP 20 | 21 | #include 22 | #include 23 | #include 24 | using namespace std; 25 | 26 | class Texture; 27 | class NSBInterpreter; 28 | class Window 29 | { 30 | public: 31 | Window(const char* WindowTitle, const int Width, const int Height); 32 | virtual ~Window(); 33 | 34 | static void PushMoveCursorEvent(int X, int Y); 35 | 36 | void Run(); 37 | void Exit(); 38 | void Select(bool Enable); 39 | void AddTexture(Texture* pTexture); 40 | void RemoveTexture(Texture* pTexture); 41 | void MoveCursor(int32_t X, int32_t Y); 42 | bool IsRunning_() { return IsRunning; } 43 | void SetFullscreen(Uint32 flags); 44 | void DrawTextures(uint32_t Diff); 45 | 46 | const int WIDTH; 47 | const int HEIGHT; 48 | protected: 49 | void HandleEvent(SDL_Event& Event); 50 | 51 | NSBInterpreter* pInterpreter; 52 | private: 53 | void Draw(); 54 | 55 | uint32_t LastDrawTime; 56 | bool IsRunning; 57 | bool EventLoop; 58 | SDL_Window* SDLWindow; 59 | SDL_GLContext GLContext; 60 | list Textures; 61 | }; 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/npengineversion.hpp.in: -------------------------------------------------------------------------------- 1 | #ifndef NPENGINE_VERSION_HPP 2 | #define NPENGINE_VERSION_HPP 3 | 4 | #define NPENGINE_VERSION "@LIBNPENGINE_VERSION@" 5 | #define NPENGINE_VERSION_MAJOR "@LIBNPENGINE_VERSION_MAJOR@" 6 | #define NPENGINE_VERSION_MINOR "@LIBNPENGINE_VERSION_MINOR@" 7 | #define NPENGINE_VERSION_PATCH "@LIBNPENGINE_VERSION_PATCH@" 8 | #define NPENGINE_VERSION_GIT "@LIBNPENGINE_VERSION_GIT@" 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/Choice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "Choice.hpp" 19 | #include "Window.hpp" 20 | 21 | Choice::Choice() : MouseOver(false), ButtonDown(false), ButtonUp(false) 22 | { 23 | Write("MouseUsual", new Name); 24 | Write("MouseOver", new Name); 25 | Write("MouseClick", new Name); 26 | for (int i = 0; i < 4; ++i) 27 | pNextFocus[i] = nullptr; 28 | } 29 | 30 | bool Choice::IsSelected(const SDL_Event& Event) 31 | { 32 | switch (Event.type) 33 | { 34 | case SDL_MOUSEBUTTONUP: Cursor(Event.button.x, Event.button.y, ButtonUp); break; 35 | case SDL_MOUSEBUTTONDOWN: Cursor(Event.button.x, Event.button.y, ButtonDown); break; 36 | case SDL_MOUSEMOTION: Cursor(Event.motion.x, Event.motion.y, MouseOver); break; 37 | case SDL_MOUSEWHEEL: Wheel(Event.wheel.x, Event.wheel.y); break; 38 | case SDL_KEYDOWN: Arrow(Event.key.keysym.sym); break; 39 | } 40 | 41 | Texture* pMouseOver = dynamic_cast(Read("MouseOver/img")); 42 | Texture* pMouseClick = dynamic_cast(Read("MouseClick/img")); 43 | Texture* pMouseUsual = dynamic_cast(Read("MouseUsual/img")); 44 | 45 | if (pMouseOver) pMouseOver->Fade(0, 0); 46 | if (pMouseClick) pMouseClick->Fade(0, 0); 47 | if (pMouseUsual) pMouseUsual->Fade(0, 0); 48 | 49 | if (MouseOver && pMouseOver) pMouseOver->Fade(0, 1000); 50 | else if (ButtonDown && pMouseClick) pMouseClick->Fade(0, 1000); 51 | else if (pMouseUsual) pMouseUsual->Fade(0, 1000); 52 | 53 | return ButtonUp; 54 | } 55 | 56 | void Choice::SetNextFocus(Choice* pNext, const string& Key) 57 | { 58 | pNextFocus[KeyToIndex(Key)] = pNext; 59 | } 60 | 61 | void Choice::Cursor(int x, int y, bool& Flag) 62 | { 63 | Texture* pTexture = dynamic_cast(Read("MouseUsual/img")); 64 | if (!pTexture) return; 65 | int x1 = pTexture->GetX(); 66 | int x2 = x1 + pTexture->GetWidth(); 67 | int y1 = pTexture->GetY(); 68 | int y2 = y1 + pTexture->GetHeight(); 69 | Flag = x > x1 && x < x2 && y > y1 && y < y2; 70 | } 71 | 72 | void Choice::Wheel(int x, int y) 73 | { 74 | if (y > 0) ChangeFocus(FOCUS_UP); 75 | else if (y < 0) ChangeFocus(FOCUS_DOWN); 76 | else if (x > 0) ChangeFocus(FOCUS_RIGHT); 77 | else if (x < 0) ChangeFocus(FOCUS_LEFT); 78 | } 79 | 80 | void Choice::Arrow(SDL_Keycode sym) 81 | { 82 | switch (sym) 83 | { 84 | case SDLK_UP: ChangeFocus(FOCUS_UP); break; 85 | case SDLK_DOWN: ChangeFocus(FOCUS_DOWN); break; 86 | case SDLK_RIGHT: ChangeFocus(FOCUS_RIGHT); break; 87 | case SDLK_LEFT: ChangeFocus(FOCUS_LEFT); break; 88 | } 89 | } 90 | 91 | void Choice::ChangeFocus(int Index) 92 | { 93 | if (Choice* pChoice = pNextFocus[Index]) 94 | if (Texture* pTexture = dynamic_cast(pChoice->Read("MouseOver/img"))) 95 | Window::PushMoveCursorEvent(pTexture->GetX() + pTexture->GetWidth() / 2, pTexture->GetY() + pTexture->GetHeight() / 2); 96 | } 97 | 98 | int Choice::KeyToIndex(const string& Key) 99 | { 100 | if (Key == "UP") return FOCUS_UP; 101 | if (Key == "DOWN") return FOCUS_DOWN; 102 | if (Key == "RIGHT") return FOCUS_RIGHT; 103 | if (Key == "LEFT") return FOCUS_LEFT; 104 | assert(false); 105 | } 106 | -------------------------------------------------------------------------------- /src/GLTexture.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "GLTexture.hpp" 19 | #include "Image.hpp" 20 | #include 21 | 22 | size_t GLFormatToVals(GLenum Format) 23 | { 24 | switch (Format) 25 | { 26 | case GL_RGBA: 27 | case GL_BGRA: 28 | return 4; 29 | case GL_RGB: 30 | case GL_BGR: 31 | return 3; 32 | case GL_LUMINANCE: 33 | return 1; 34 | } 35 | assert(false); 36 | } 37 | 38 | GLTexture::GLTexture() : 39 | Width(0), Height(0), 40 | GLTextureID(GL_INVALID_VALUE) 41 | { 42 | } 43 | 44 | GLTexture::~GLTexture() 45 | { 46 | glDeleteTextures(1, &GLTextureID); 47 | } 48 | 49 | void GLTexture::Draw(int X, int Y, const string& Filename) 50 | { 51 | Image Img; 52 | Img.LoadImage(Filename); 53 | glBindTexture(GL_TEXTURE_2D, GLTextureID); 54 | glTexSubImage2D(GL_TEXTURE_2D, 0, X, Y, Img.GetWidth(), Img.GetHeight(), Img.GetFormat(), GL_UNSIGNED_BYTE, Img.GetPixels()); 55 | } 56 | 57 | void GLTexture::Draw(float X, float Y, float Width, float Height) 58 | { 59 | static const float x[4] = {0, X, X, 0}, y[4] = {0, 0, Y, Y}; 60 | Draw(x, y); 61 | } 62 | 63 | void GLTexture::Draw(const float* xa, const float* ya) 64 | { 65 | static const float x[4] = {0, 1, 1, 0}, y[4] = {0, 0, 1, 1}; 66 | glBindTexture(GL_TEXTURE_2D, GLTextureID); 67 | glBegin(GL_QUADS); 68 | for (int i = 0; i < 4; ++i) 69 | { 70 | glTexCoord2f(x[i], y[i]); 71 | glVertex2f(xa[i], ya[i]); 72 | } 73 | glEnd(); 74 | } 75 | 76 | void GLTexture::CreateFromScreen(Window* pWindow) 77 | { 78 | Image Img; 79 | Img.LoadScreen(pWindow); 80 | CreateFromImage(&Img); 81 | } 82 | 83 | void GLTexture::CreateFromColor(int Width, int Height, uint32_t Color) 84 | { 85 | Image Img; 86 | Img.LoadColor(Width, Height, Color); 87 | CreateFromImage(&Img); 88 | } 89 | 90 | void GLTexture::CreateFromFile(const string& Filename, bool Mask) 91 | { 92 | Image Img; 93 | Img.LoadImage(Filename, Mask); 94 | CreateFromImage(&Img); 95 | } 96 | 97 | void GLTexture::CreateFromImage(Image* pImage) 98 | { 99 | Create(pImage->GetPixels(), pImage->GetFormat(), pImage->GetWidth(), pImage->GetHeight()); 100 | } 101 | 102 | void GLTexture::CreateFromImageClip(Image* pImage, int ClipX, int ClipY, int ClipWidth, int ClipHeight) 103 | { 104 | size_t NumVals = GLFormatToVals(pImage->GetFormat()); 105 | uint8_t* pClipped = new uint8_t[ClipWidth * ClipHeight * NumVals]; 106 | for (int i = 0; i < ClipHeight; ++i) 107 | memcpy(pClipped + i * ClipWidth * NumVals, pImage->GetPixels() + (pImage->GetWidth() * (ClipY + i) + ClipX) * NumVals, ClipWidth * NumVals); 108 | 109 | Create(pClipped, pImage->GetFormat(), ClipWidth, ClipHeight); 110 | delete[] pClipped; 111 | } 112 | 113 | void GLTexture::CreateFromFileClip(const string& Filename, int ClipX, int ClipY, int ClipWidth, int ClipHeight) 114 | { 115 | Image Img; 116 | Img.LoadImage(Filename); 117 | CreateFromImageClip(&Img, ClipX, ClipY, ClipWidth, ClipHeight); 118 | } 119 | 120 | void GLTexture::CreateEmpty(int Width, int Height) 121 | { 122 | Create(0, GL_RGB, Width, Height); 123 | } 124 | 125 | void GLTexture::Create(uint8_t* Pixels, GLenum Format, int W, int H) 126 | { 127 | Width = W; 128 | Height = H; 129 | glDeleteTextures(1, &GLTextureID); 130 | glGenTextures(1, &GLTextureID); 131 | glBindTexture(GL_TEXTURE_2D, GLTextureID); 132 | SetSmoothing(false); 133 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Width, Height, 0, Format, GL_UNSIGNED_BYTE, Pixels); 134 | } 135 | 136 | void GLTexture::SetSmoothing(bool Set) 137 | { 138 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Set ? GL_LINEAR : GL_NEAREST); 139 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, Set ? GL_LINEAR : GL_NEAREST); 140 | } 141 | -------------------------------------------------------------------------------- /src/Image.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include 19 | #include "Image.hpp" 20 | #include "ResourceMgr.hpp" 21 | #include "Window.hpp" 22 | #include 23 | #include 24 | #include 25 | 26 | Image::Image() : Format(-1), Width(0), Height(0), pPixels(0) 27 | { 28 | } 29 | 30 | Image::~Image() 31 | { 32 | delete[] pPixels; 33 | } 34 | 35 | void Image::LoadColor(int Width, int Height, uint32_t Color) 36 | { 37 | this->Width = Width; 38 | this->Height = Height; 39 | pPixels = new uint8_t[Width * Height * 4]; 40 | for (int i = 0; i < Width * Height; ++i) 41 | memcpy(pPixels + i * 4, &Color, 4); 42 | Format = GL_BGRA; 43 | } 44 | 45 | void Image::LoadImage(const string& Filename, bool Mask) 46 | { 47 | uint32_t Size; 48 | uint8_t* pData = (uint8_t*)sResourceMgr->Read(Filename, Size); 49 | if (!pData) 50 | return; 51 | 52 | if (Filename.substr(Filename.size() - 3) == "jpg") 53 | { 54 | pPixels = LoadJPEG(pData, Size); 55 | } 56 | else if (Filename.substr(Filename.size() - 3) == "png") 57 | { 58 | pPixels = LoadPNG(pData, Size, Mask ? PNG_FORMAT_GRAY : PNG_FORMAT_RGBA); 59 | Format = Mask ? GL_LUMINANCE : GL_RGBA; 60 | } 61 | else 62 | cout << Filename << " is neither .jpg nor .png!" << endl; 63 | 64 | delete[] pData; 65 | } 66 | 67 | void Image::LoadScreen(Window* pWindow) 68 | { 69 | Format = GL_BGRA; 70 | Width = pWindow->WIDTH; 71 | Height = pWindow->HEIGHT; 72 | pPixels = new uint8_t[Width * Height * 4]; 73 | glMatrixMode(GL_PROJECTION); 74 | glPushMatrix(); 75 | glLoadIdentity(); 76 | glOrtho(0, Width, 0, Height, -1, 1); 77 | pWindow->DrawTextures(0); 78 | glReadBuffer(GL_BACK); 79 | glReadPixels(0, 0, Width, Height, GL_BGRA, GL_UNSIGNED_BYTE, pPixels); 80 | glPopMatrix(); 81 | } 82 | 83 | uint8_t* Image::LoadPNG(uint8_t* pMem, uint32_t Size, uint8_t Format) 84 | { 85 | png_image png; 86 | memset(&png, 0, sizeof(png_image)); 87 | png.version = PNG_IMAGE_VERSION; 88 | 89 | if (!png_image_begin_read_from_memory(&png, pMem, Size)) 90 | return nullptr; 91 | 92 | png.format = Format; 93 | uint8_t* pData = new (nothrow) uint8_t[PNG_IMAGE_SIZE(png)]; 94 | if (!pData) 95 | { 96 | png_image_free(&png); 97 | return nullptr; 98 | } 99 | 100 | if (!png_image_finish_read(&png, NULL, pData, 0, NULL)) 101 | { 102 | delete[] pData; 103 | return nullptr; 104 | } 105 | 106 | Width = png.width; 107 | Height = png.height; 108 | return pData; 109 | } 110 | 111 | uint8_t* Image::LoadJPEG(uint8_t* pMem, uint32_t Size) 112 | { 113 | struct jpeg_decompress_struct jpeg; 114 | struct jpeg_error_mgr err; 115 | 116 | jpeg.err = jpeg_std_error(&err); 117 | jpeg_create_decompress(&jpeg); 118 | jpeg_mem_src(&jpeg, pMem, Size); 119 | jpeg_read_header(&jpeg, 1); 120 | jpeg_start_decompress(&jpeg); 121 | 122 | Width = jpeg.output_width; 123 | Height = jpeg.output_height; 124 | jpeg.out_color_space = JCS_EXT_RGBX; 125 | Format = GL_RGBA; 126 | 127 | uint8_t* data = new uint8_t[Width * Height * 4]; 128 | for (int y = 0; y < Height; ++y) 129 | { 130 | uint8_t* ptr = data + Width * 4 * y; 131 | jpeg_read_scanlines(&jpeg, &ptr, 1); 132 | } 133 | 134 | jpeg_finish_decompress(&jpeg); 135 | jpeg_destroy_decompress(&jpeg); 136 | return data; 137 | } 138 | -------------------------------------------------------------------------------- /src/Movie.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2013-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "Movie.hpp" 19 | #include "Window.hpp" 20 | 21 | Movie::Movie(const string& FileName, Window* pWindow, int32_t Priority, bool Alpha, bool Audio) : 22 | Playable(FileName), 23 | Alpha(Alpha) 24 | { 25 | SetPriority(Priority); 26 | InitVideo(pWindow); 27 | if (Audio) 28 | InitAudio(); 29 | } 30 | 31 | Movie::~Movie() 32 | { 33 | } 34 | 35 | void Movie::UpdateSample() 36 | { 37 | GstSample* sample = gst_app_sink_pull_sample(Appsink); 38 | if (!sample) 39 | return; 40 | 41 | GstCaps* caps = gst_sample_get_caps(sample); 42 | if (!caps) 43 | return; 44 | 45 | GstStructure* s = gst_caps_get_structure(caps, 0); 46 | gint width, height; 47 | gst_structure_get_int(s, "width", &width); 48 | gst_structure_get_int(s, "height", &height); 49 | GstBuffer* buffer = gst_sample_get_buffer(sample); 50 | GstMapInfo map; 51 | if (gst_buffer_map(buffer, &map, GST_MAP_READ)) 52 | { 53 | Create(map.data, GL_RGB, width, height); 54 | gst_buffer_unmap(buffer, &map); 55 | } 56 | gst_sample_unref(sample); 57 | } 58 | 59 | void Movie::Draw(uint32_t Diff) 60 | { 61 | if (Playing) UpdateSample(); 62 | Texture::Draw(Diff); 63 | } 64 | 65 | void Movie::InitVideo(Window* pWindow) 66 | { 67 | VideoBin = gst_bin_new("videobin"); 68 | GstElement* VideoConv = gst_element_factory_make("videoconvert", "vconv"); 69 | GstPad* VideoPad = gst_element_get_static_pad(VideoConv, "sink"); 70 | Appsink = (GstAppSink*)gst_element_factory_make("appsink", "sink"); 71 | 72 | GstCaps* caps = gst_caps_from_string("video/x-raw,format=RGB"); 73 | gst_app_sink_set_caps(Appsink, caps); 74 | gst_caps_unref(caps); 75 | 76 | gst_bin_add(GST_BIN(VideoBin), VideoConv); 77 | gst_bin_add(GST_BIN(VideoBin), (GstElement*)Appsink); 78 | 79 | gst_element_link_many(VideoConv, (GstElement*)Appsink, nullptr); 80 | 81 | gst_element_add_pad(VideoBin, gst_ghost_pad_new("sink", VideoPad)); 82 | gst_object_unref(VideoPad); 83 | gst_bin_add(GST_BIN(Pipeline), VideoBin); 84 | } 85 | -------------------------------------------------------------------------------- /src/NSBContext.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "NSBContext.hpp" 19 | #include "Text.hpp" 20 | #include "scriptfile.hpp" 21 | #include "nsbconstants.hpp" 22 | 23 | NSBContext::NSBContext(const string& Name) : pText(nullptr), pObject(nullptr), Name(Name), WaitTime(0), Elapsed(0), WaitInterrupt(false), Active(false) 24 | { 25 | } 26 | 27 | NSBContext::~NSBContext() 28 | { 29 | } 30 | 31 | bool NSBContext::Call(ScriptFile* pScript, const string& Symbol) 32 | { 33 | uint32_t CodeLine = pScript->GetSymbol(Symbol); 34 | if (CodeLine == NSB_INVALIDE_LINE && Symbol.substr(0, 8) == "function") 35 | if (!(pScript = sResourceMgr->ResolveSymbol(Symbol, CodeLine))) 36 | return false; 37 | CallStack.push({pScript, CodeLine - 1}); 38 | return true; 39 | } 40 | 41 | void NSBContext::Jump(const string& Symbol) 42 | { 43 | uint32_t CodeLine = GetScript()->GetSymbol(Symbol); 44 | if (CodeLine != NSB_INVALIDE_LINE) 45 | GetFrame()->SourceLine = CodeLine - 1; 46 | } 47 | 48 | void NSBContext::Break() 49 | { 50 | Jump(BreakStack.top()); 51 | } 52 | 53 | const string& NSBContext::GetScriptName() 54 | { 55 | return GetScript()->GetName(); 56 | } 57 | 58 | ScriptFile* NSBContext::GetScript() 59 | { 60 | return GetFrame()->pScript; 61 | } 62 | 63 | Line* NSBContext::GetLine() 64 | { 65 | return GetScript()->GetLine(GetLineNumber()); 66 | } 67 | 68 | const string& NSBContext::GetParam(uint32_t Index) 69 | { 70 | return GetLine()->Params[Index]; 71 | } 72 | 73 | int NSBContext::GetNumParams() 74 | { 75 | return GetLine()->Params.size(); 76 | } 77 | 78 | uint32_t NSBContext::GetLineNumber() 79 | { 80 | return GetFrame()->SourceLine; 81 | } 82 | 83 | uint32_t NSBContext::GetMagic() 84 | { 85 | return GetLine()->Magic; 86 | } 87 | 88 | NSBContext::StackFrame* NSBContext::GetFrame() 89 | { 90 | return &CallStack.top(); 91 | } 92 | 93 | uint32_t NSBContext::Advance() 94 | { 95 | GetFrame()->SourceLine++; 96 | return GetMagic(); 97 | } 98 | 99 | void NSBContext::Rewind() 100 | { 101 | GetFrame()->SourceLine--; 102 | } 103 | 104 | void NSBContext::Return() 105 | { 106 | CallStack.pop(); 107 | } 108 | 109 | void NSBContext::PushBreak() 110 | { 111 | BreakStack.push(GetParam(0)); 112 | } 113 | 114 | void NSBContext::PopBreak() 115 | { 116 | BreakStack.pop(); 117 | } 118 | 119 | void NSBContext::WaitText(Text* pText, int32_t Time) 120 | { 121 | this->pText = pText; 122 | Wait(Time); 123 | } 124 | 125 | void NSBContext::WaitAction(Object* pObject, int32_t Time) 126 | { 127 | this->pObject = pObject; 128 | Wait(Time); 129 | } 130 | 131 | void NSBContext::WaitKey(int32_t Time) 132 | { 133 | Wait(Time, true); 134 | } 135 | 136 | void NSBContext::Wait(int32_t Time, bool Interrupt) 137 | { 138 | WaitInterrupt = Interrupt; 139 | WaitTime = Time; 140 | Elapsed = 0; 141 | } 142 | 143 | void NSBContext::Wake() 144 | { 145 | pObject = nullptr; 146 | pText = nullptr; 147 | WaitInterrupt = false; 148 | WaitTime = 0; 149 | } 150 | 151 | void NSBContext::TryWake() 152 | { 153 | if (pObject && pObject->Action()) 154 | Wake(); 155 | } 156 | 157 | void NSBContext::OnClick() 158 | { 159 | if (WaitInterrupt || (pText && !pText->Advance())) 160 | Wake(); 161 | } 162 | 163 | bool NSBContext::IsStarving() 164 | { 165 | return CallStack.empty(); 166 | } 167 | 168 | bool NSBContext::IsSleeping() 169 | { 170 | return pText || Elapsed < WaitTime; 171 | } 172 | 173 | bool NSBContext::IsActive() 174 | { 175 | return Active; 176 | } 177 | 178 | void NSBContext::Start() 179 | { 180 | Active = true; 181 | } 182 | 183 | void NSBContext::Request(int32_t State) 184 | { 185 | switch (State) 186 | { 187 | case Nsb::START: 188 | Start(); 189 | break; 190 | case Nsb::PAUSE: 191 | break; 192 | case Nsb::RESUME: 193 | break; 194 | } 195 | } 196 | 197 | const string& NSBContext::GetName() 198 | { 199 | return Name; 200 | } 201 | 202 | void NSBContext::WriteTrace(ostream& Stream) 203 | { 204 | if (!GetScript()) 205 | return; 206 | 207 | stack Returns = CallStack; 208 | while (!Returns.empty()) 209 | { 210 | Stream << Returns.top().pScript->GetName() << " at " << Returns.top().SourceLine << endl; 211 | Returns.pop(); 212 | } 213 | } 214 | 215 | void NSBContext::Update(uint32_t Diff) 216 | { 217 | Elapsed += Diff; 218 | } 219 | -------------------------------------------------------------------------------- /src/NSBDebugger.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "NSBInterpreter.hpp" 19 | #include "NSBContext.hpp" 20 | #include "Window.hpp" 21 | #include "nsbmagic.hpp" 22 | #include "scriptfile.hpp" 23 | #include 24 | 25 | void NSBInterpreter::StartDebugger() 26 | { 27 | if (!pDebuggerThread) 28 | pDebuggerThread = new thread(bind(&NSBInterpreter::DebuggerMain, this)); 29 | DbgBreak(true); 30 | } 31 | 32 | void NSBInterpreter::SetBreakpoint(const string& Script, int32_t LineNumber) 33 | { 34 | if (ScriptFile* pScript = sResourceMgr->GetScriptFile(Script)) 35 | { 36 | if (pScript->GetLine(LineNumber)) 37 | Breakpoints.push_back(make_pair(Script, LineNumber)); 38 | } 39 | else 40 | cout << "Cannot set breakpoint " << Script << ":" << LineNumber << endl; 41 | } 42 | 43 | void NSBInterpreter::PrintVariable(Variable* pVar) 44 | { 45 | cout << pVar->Name << " = "; 46 | if (pVar->IsInt()) 47 | cout << pVar->ToInt() << endl; 48 | else if (pVar->IsString()) 49 | cout << pVar->ToString() << endl; 50 | } 51 | 52 | void NSBInterpreter::DebuggerTick() 53 | { 54 | if (DbgStepping || LogCalls) 55 | cout << pContext->GetScriptName() << ":" 56 | << pContext->GetLineNumber() << " " 57 | << pContext->GetLine()->Stringify() << endl; 58 | 59 | if (DbgStepping) 60 | { 61 | RunInterpreter = false; 62 | return; 63 | } 64 | 65 | // Breakpoint 66 | for (auto i : Breakpoints) 67 | { 68 | if (i.first == pContext->GetScriptName() && 69 | i.second == pContext->GetLineNumber()) 70 | { 71 | DbgBreak(true); 72 | return; 73 | } 74 | } 75 | } 76 | 77 | void NSBInterpreter::DbgBreak(bool Break) 78 | { 79 | if (Break) cout << "Breakpoint hit!" << endl; 80 | DbgStepping = Break; 81 | RunInterpreter = !Break; 82 | } 83 | 84 | void NSBInterpreter::Inspect(int32_t n) 85 | { 86 | for (auto i : Threads) 87 | { 88 | cout << "\nThread " << i->GetName() << ":\n"; 89 | ScriptFile* pScript = i->GetScript(); 90 | uint32_t SourceIter = i->GetLineNumber(); 91 | for (uint32_t i = SourceIter - n; i < SourceIter + n + 1; ++i) 92 | cout << ((i == SourceIter) ? " > " : " ") << pScript->GetLine(i)->Stringify() << endl; 93 | } 94 | } 95 | 96 | void NSBInterpreter::DebuggerMain() 97 | { 98 | string OldCommand; 99 | while (pWindow->IsRunning_()) 100 | { 101 | string Command; 102 | getline(cin, Command); 103 | if (Command.empty()) 104 | Command = OldCommand; 105 | else OldCommand = Command; 106 | 107 | // Step 108 | if (Command == "s") 109 | RunInterpreter = true; 110 | // Continue 111 | else if (Command == "c") 112 | DbgBreak(false); 113 | // Quit 114 | else if (Command == "q") 115 | Exit(); 116 | // Wait (Activate debugger) 117 | else if (Command == "w") 118 | DbgBreak(true); 119 | // Log 120 | else if (Command == "l") 121 | LogCalls = !LogCalls; 122 | // Thread Trace 123 | else if (Command == "t") 124 | { 125 | for (auto i : Threads) 126 | { 127 | cout << "\nThread " << i->GetName() << ":\n"; 128 | i->WriteTrace(cout); 129 | } 130 | } 131 | else 132 | { 133 | vector Tokens; 134 | boost::split(Tokens, Command, boost::is_any_of(" :")); 135 | 136 | // Breakpoint 137 | if (Tokens.size() == 3 && Tokens[0] == "b") 138 | { 139 | try 140 | { 141 | SetBreakpoint(Tokens[1], stoi(Tokens[2])); 142 | } catch (...) { cout << "Bad command!" << endl; } 143 | } 144 | // Breakpoint Clear 145 | else if (Tokens.size() == 2 && Tokens[0] == "b" && Tokens[1] == "c") 146 | { 147 | Breakpoints.clear(); 148 | } 149 | // Print 150 | else if (Tokens.size() == 2 && Tokens[0] == "p") 151 | { 152 | PrintVariable(GetVar(Tokens[1])); 153 | } 154 | // Print Array 155 | else if (Tokens.size() == 3 && Tokens[0] == "p" && Tokens[1] == "a") 156 | { 157 | // TODO: print recursively 158 | PrintVariable(GetVar(Tokens[2])); 159 | } 160 | // Inspect surrounding code 161 | else if (Tokens.size() == 2 && Tokens[0] == "i") 162 | { 163 | try 164 | { 165 | Inspect(stoi(Tokens[1])); 166 | } catch (...) { cout << "Bad command!" << endl; } 167 | } 168 | // Dump Variables 169 | else if (Tokens.size() == 2 && Tokens[0] == "d" && Tokens[1] == "v") 170 | { 171 | for (auto i : VariableHolder.Cache) 172 | { 173 | assert(i.first == i.second->Name); 174 | PrintVariable(i.second); 175 | } 176 | } 177 | else 178 | cout << "Bad command!" << endl; 179 | } 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/NSBInterpreter.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "NSBInterpreter.hpp" 19 | #include "NSBContext.hpp" 20 | #include "Texture.hpp" 21 | #include "Image.hpp" 22 | #include "Window.hpp" 23 | #include "Movie.hpp" 24 | #include "Text.hpp" 25 | #include "Scrollbar.hpp" 26 | #include "nsbmagic.hpp" 27 | #include "nsbconstants.hpp" 28 | #include "scriptfile.hpp" 29 | #include "npafile.hpp" 30 | #include "fscommon.hpp" 31 | #include "buffer.hpp" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #define NSB_ERROR(MSG1, MSG2) cout << __PRETTY_FUNCTION__ << ": " << MSG1 << " " << MSG2 << endl; 39 | #define NSB_VARARGS 0xFF 40 | 41 | extern "C" { void gst_init(int* argc, char** argv[]); } 42 | 43 | NSBInterpreter::NSBInterpreter(Window* pWindow) : 44 | pDebuggerThread(nullptr), 45 | LogCalls(false), 46 | DbgStepping(false), 47 | RunInterpreter(true), 48 | SkipHack(false), 49 | pWindow(pWindow), 50 | pContext(nullptr), 51 | Builtins(MAGIC_UNK119 + 1, {nullptr, 0}) 52 | { 53 | gst_init(nullptr, nullptr); 54 | srand(time(0)); 55 | 56 | Builtins[MAGIC_FUNCTION_DECLARATION] = { &NSBInterpreter::FunctionDeclaration, 0 }; 57 | Builtins[MAGIC_CALL_FUNCTION] = { &NSBInterpreter::CallFunction, 0 }; 58 | Builtins[MAGIC_CALL_SCENE] = { &NSBInterpreter::CallScene, 0 }; 59 | Builtins[MAGIC_CALL_CHAPTER] = { &NSBInterpreter::CallChapter, 0 }; 60 | Builtins[MAGIC_CMP_LOGICAL_AND] = { &NSBInterpreter::CmpLogicalAnd, 2 }; 61 | Builtins[MAGIC_CMP_LOGICAL_OR] = { &NSBInterpreter::CmpLogicalOr, 2 }; 62 | Builtins[MAGIC_CMP_GE] = { &NSBInterpreter::CmpGE, 2 }; 63 | Builtins[MAGIC_CMP_LE] = { &NSBInterpreter::CmpLE, 2 }; 64 | Builtins[MAGIC_CMP_GREATER] = { &NSBInterpreter::CmpGreater, 2 }; 65 | Builtins[MAGIC_CMP_LESS] = { &NSBInterpreter::CmpLess, 2 }; 66 | Builtins[MAGIC_CMP_EQUAL] = { &NSBInterpreter::CmpEqual, 2 }; 67 | Builtins[MAGIC_CMP_NE] = { &NSBInterpreter::CmpNE, 2 }; 68 | Builtins[MAGIC_NOT_EXPRESSION] = { &NSBInterpreter::NotExpression, 1 }; 69 | Builtins[MAGIC_ADD_EXPRESSION] = { &NSBInterpreter::AddExpression, 2 }; 70 | Builtins[MAGIC_SUB_EXPRESSION] = { &NSBInterpreter::SubExpression, 2 }; 71 | Builtins[MAGIC_MUL_EXPRESSION] = { &NSBInterpreter::MulExpression, 2 }; 72 | Builtins[MAGIC_DIV_EXPRESSION] = { &NSBInterpreter::DivExpression, 2 }; 73 | Builtins[MAGIC_MOD_EXPRESSION] = { &NSBInterpreter::ModExpression, 2 }; 74 | Builtins[MAGIC_INCREMENT] = { &NSBInterpreter::Increment, 1 }; 75 | Builtins[MAGIC_DECREMENT] = { &NSBInterpreter::Decrement, 1 }; 76 | Builtins[MAGIC_LITERAL] = { &NSBInterpreter::Literal, 0 }; 77 | Builtins[MAGIC_ASSIGN] = { &NSBInterpreter::Assign, 1 }; 78 | Builtins[MAGIC_VARIABLE] = { &NSBInterpreter::Get, 0 }; 79 | Builtins[MAGIC_SCOPE_BEGIN] = { &NSBInterpreter::ScopeBegin, 0 }; 80 | Builtins[MAGIC_SCOPE_END] = { &NSBInterpreter::ScopeEnd, 0 }; 81 | Builtins[MAGIC_RETURN] = { &NSBInterpreter::Return, 0 }; 82 | Builtins[MAGIC_END_FUNCTION] = { &NSBInterpreter::Return, 0 }; 83 | Builtins[MAGIC_END_SCENE] = { &NSBInterpreter::Return, 0 }; 84 | Builtins[MAGIC_END_CHAPTER] = { &NSBInterpreter::Return, 0 }; 85 | Builtins[MAGIC_IF] = { &NSBInterpreter::If, 1 }; 86 | Builtins[MAGIC_WHILE] = { &NSBInterpreter::While, 1 }; 87 | Builtins[MAGIC_WHILE_END] = { &NSBInterpreter::WhileEnd, 0 }; 88 | Builtins[MAGIC_SELECT] = { &NSBInterpreter::Select, 0 }; 89 | Builtins[MAGIC_SELECT_END] = { &NSBInterpreter::SelectEnd, 0 }; 90 | Builtins[MAGIC_SELECT_BREAK_END] = { &NSBInterpreter::SelectBreakEnd, 0 }; 91 | Builtins[MAGIC_BREAK] = { &NSBInterpreter::Break, 0 }; 92 | Builtins[MAGIC_JUMP] = { &NSBInterpreter::Jump, 0 }; 93 | Builtins[MAGIC_ADD_ASSIGN] = { &NSBInterpreter::AddAssign, 1 }; 94 | Builtins[MAGIC_SUB_ASSIGN] = { &NSBInterpreter::SubAssign, 1 }; 95 | Builtins[MAGIC_MOD_ASSIGN] = { &NSBInterpreter::ModAssign, 1 }; 96 | Builtins[MAGIC_WRITE_FILE] = { &NSBInterpreter::WriteFile, 2 }; 97 | Builtins[MAGIC_READ_FILE] = { &NSBInterpreter::ReadFile, 1 }; 98 | Builtins[MAGIC_CREATE_TEXTURE] = { &NSBInterpreter::CreateTexture, 5 }; 99 | Builtins[MAGIC_IMAGE_HORIZON] = { &NSBInterpreter::ImageHorizon, 1 }; 100 | Builtins[MAGIC_IMAGE_VERTICAL] = { &NSBInterpreter::ImageVertical, 1 }; 101 | Builtins[MAGIC_TIME] = { &NSBInterpreter::Time, 0 }; 102 | Builtins[MAGIC_STR_STR] = { &NSBInterpreter::StrStr, 2 }; 103 | Builtins[MAGIC_EXIT] = { &NSBInterpreter::Exit, 0 }; 104 | Builtins[MAGIC_CURSOR_POSITION] = { &NSBInterpreter::CursorPosition, 2 }; 105 | Builtins[MAGIC_MOVE_CURSOR] = { &NSBInterpreter::MoveCursor, 2 }; 106 | Builtins[MAGIC_POSITION] = { &NSBInterpreter::Position, 3 }; 107 | Builtins[MAGIC_WAIT] = { &NSBInterpreter::Wait, 1 }; 108 | Builtins[MAGIC_WAIT_KEY] = { &NSBInterpreter::WaitKey, NSB_VARARGS }; 109 | Builtins[MAGIC_NEGA_EXPRESSION] = { &NSBInterpreter::NegaExpression, 1 }; 110 | Builtins[MAGIC_SYSTEM] = { &NSBInterpreter::System, 3 }; 111 | Builtins[MAGIC_STRING] = { &NSBInterpreter::String, NSB_VARARGS }; 112 | Builtins[MAGIC_VARIABLE_VALUE] = { &NSBInterpreter::VariableValue, NSB_VARARGS }; 113 | Builtins[MAGIC_CREATE_PROCESS] = { &NSBInterpreter::CreateProcess, 5 }; 114 | Builtins[MAGIC_COUNT] = { &NSBInterpreter::Count, 1 }; 115 | Builtins[MAGIC_ARRAY] = { &NSBInterpreter::Array, NSB_VARARGS }; 116 | Builtins[MAGIC_SUB_SCRIPT] = { &NSBInterpreter::SubScript, 0 }; 117 | Builtins[MAGIC_ASSOC_ARRAY] = { &NSBInterpreter::AssocArray, NSB_VARARGS }; 118 | Builtins[MAGIC_MODULE_FILE_NAME] = { &NSBInterpreter::ModuleFileName, 0 }; 119 | Builtins[MAGIC_REQUEST] = { &NSBInterpreter::Request, 2 }; 120 | Builtins[MAGIC_SET_VERTEX] = { &NSBInterpreter::SetVertex, 3 }; 121 | Builtins[MAGIC_ZOOM] = { &NSBInterpreter::Zoom, 6 }; 122 | Builtins[MAGIC_MOVE] = { &NSBInterpreter::Move, 6 }; 123 | Builtins[MAGIC_SET_SHADE] = { &NSBInterpreter::SetShade, 2 }; 124 | Builtins[MAGIC_DRAW_TO_TEXTURE] = { &NSBInterpreter::DrawToTexture, 4 }; 125 | Builtins[MAGIC_CREATE_RENDER_TEXTURE] = { &NSBInterpreter::CreateRenderTexture, 4 }; 126 | Builtins[MAGIC_DRAW_TRANSITION] = { &NSBInterpreter::DrawTransition, 8 }; 127 | Builtins[MAGIC_CREATE_COLOR] = { &NSBInterpreter::CreateColor, 7 }; 128 | Builtins[MAGIC_LOAD_IMAGE] = { &NSBInterpreter::LoadImage, 2 }; 129 | Builtins[MAGIC_FADE] = { &NSBInterpreter::Fade, 5 }; 130 | Builtins[MAGIC_DELETE] = { &NSBInterpreter::Delete, 1 }; 131 | Builtins[MAGIC_CLEAR_PARAMS] = { &NSBInterpreter::ClearParams, 0 }; 132 | Builtins[MAGIC_SET_LOOP] = { &NSBInterpreter::SetLoop, 2 }; 133 | Builtins[MAGIC_SET_VOLUME] = { &NSBInterpreter::SetVolume, 4 }; 134 | Builtins[MAGIC_SET_LOOP_POINT] = { &NSBInterpreter::SetLoopPoint, 3 }; 135 | Builtins[MAGIC_CREATE_SOUND] = { &NSBInterpreter::CreateSound, 3 }; 136 | Builtins[MAGIC_REMAIN_TIME] = { &NSBInterpreter::RemainTime, 1 }; 137 | Builtins[MAGIC_CREATE_MOVIE] = { &NSBInterpreter::CreateMovie, 8 }; 138 | Builtins[MAGIC_DURATION_TIME] = { &NSBInterpreter::DurationTime, 1 }; 139 | Builtins[MAGIC_SET_FREQUENCY] = { &NSBInterpreter::SetFrequency, 4 }; 140 | Builtins[MAGIC_SET_PAN] = { &NSBInterpreter::SetPan, 4 }; 141 | Builtins[MAGIC_SET_ALIAS] = { &NSBInterpreter::SetAlias, 2 }; 142 | Builtins[MAGIC_CREATE_NAME] = { &NSBInterpreter::CreateName, 1 }; 143 | Builtins[MAGIC_CREATE_WINDOW] = { &NSBInterpreter::CreateWindow, 7 }; 144 | Builtins[MAGIC_CREATE_CHOICE] = { &NSBInterpreter::CreateChoice, NSB_VARARGS }; 145 | Builtins[MAGIC_CASE] = { &NSBInterpreter::Case, 0 }; 146 | Builtins[MAGIC_CASE_END] = { &NSBInterpreter::CaseEnd, 0 }; 147 | Builtins[MAGIC_SET_NEXT_FOCUS] = { &NSBInterpreter::SetNextFocus, 3 }; 148 | Builtins[MAGIC_PASSAGE_TIME] = { &NSBInterpreter::PassageTime, 1 }; 149 | Builtins[MAGIC_PARSE_TEXT] = { &NSBInterpreter::ParseText, 0 }; 150 | Builtins[MAGIC_LOAD_TEXT] = { &NSBInterpreter::LoadText, 7 }; 151 | Builtins[MAGIC_WAIT_TEXT] = { &NSBInterpreter::WaitText, 2 }; 152 | Builtins[MAGIC_LOCK_VIDEO] = { &NSBInterpreter::LockVideo, 1 }; 153 | Builtins[MAGIC_SAVE] = { &NSBInterpreter::Save, 1 }; 154 | Builtins[MAGIC_DELETE_SAVE_FILE] = { &NSBInterpreter::DeleteSaveFile, 1}; 155 | Builtins[MAGIC_CONQUEST] = { &NSBInterpreter::Conquest, 3 }; 156 | Builtins[MAGIC_CLEAR_SCORE] = { &NSBInterpreter::ClearScore, 1 }; 157 | Builtins[MAGIC_CLEAR_BACKLOG] = { &NSBInterpreter::ClearBacklog, 0 }; 158 | Builtins[MAGIC_SET_FONT] = { &NSBInterpreter::SetFont, 6 }; 159 | Builtins[MAGIC_SET_SHORTCUT] = { &NSBInterpreter::SetShortcut, 2 }; 160 | Builtins[MAGIC_CREATE_CLIP_TEXTURE] = { &NSBInterpreter::CreateClipTexture, 9 }; 161 | Builtins[MAGIC_EXIST_SAVE] = { &NSBInterpreter::ExistSave, 1 }; 162 | Builtins[MAGIC_WAIT_ACTION] = { &NSBInterpreter::WaitAction, NSB_VARARGS }; 163 | Builtins[MAGIC_LOAD] = { &NSBInterpreter::Load, 1 }; 164 | Builtins[MAGIC_SET_BACKLOG] = { &NSBInterpreter::SetBacklog, 3 }; 165 | Builtins[MAGIC_CREATE_TEXT] = { &NSBInterpreter::CreateText, 7 }; 166 | Builtins[MAGIC_AT_EXPRESSION] = { &NSBInterpreter::AtExpression, 1 }; 167 | Builtins[MAGIC_RANDOM] = { &NSBInterpreter::Random, 1 }; 168 | Builtins[MAGIC_CREATE_EFFECT] = { &NSBInterpreter::CreateEffect, 7 }; 169 | Builtins[MAGIC_SET_TONE] = { &NSBInterpreter::SetTone, 2 }; 170 | Builtins[MAGIC_DATE_TIME] = { &NSBInterpreter::DateTime, 6}; 171 | Builtins[MAGIC_SHAKE] = { &NSBInterpreter::Shake, 9}; 172 | Builtins[MAGIC_MOVIE_PLAY] = { &NSBInterpreter::MoviePlay, 2}; 173 | Builtins[MAGIC_SET_STREAM] = { &NSBInterpreter::SetStream, 2}; 174 | Builtins[MAGIC_WAIT_PLAY] = { &NSBInterpreter::WaitPlay, 2}; 175 | Builtins[MAGIC_WAIT_FADE] = { &NSBInterpreter::WaitFade, 2}; 176 | Builtins[MAGIC_SOUND_AMPLITUDE] = { &NSBInterpreter::SoundAmplitude, 2}; 177 | Builtins[MAGIC_ROTATE] = { &NSBInterpreter::Rotate, 7}; 178 | Builtins[MAGIC_MESSAGE] = { &NSBInterpreter::Message, 4}; 179 | Builtins[MAGIC_INTEGER] = { &NSBInterpreter::Integer, 1}; 180 | Builtins[MAGIC_CREATE_SCROLLBAR] = { &NSBInterpreter::CreateScrollbar, 14}; 181 | Builtins[MAGIC_SET_SCROLLBAR_VALUE] = { &NSBInterpreter::SetScrollbarValue, 2}; 182 | Builtins[MAGIC_SET_SCROLLBAR_WHEEL_AREA] = { &NSBInterpreter::SetScrollbarWheelArea, 5}; 183 | Builtins[MAGIC_SCROLLBAR_VALUE] = { &NSBInterpreter::ScrollbarValue, 1}; 184 | Builtins[MAGIC_CREATE_STENCIL] = { &NSBInterpreter::CreateStencil, 7}; 185 | Builtins[MAGIC_CREATE_MASK] = { &NSBInterpreter::CreateMask, 6}; 186 | 187 | pContext = new NSBContext("__main__"); 188 | pContext->Start(); 189 | Threads.push_back(pContext); 190 | } 191 | 192 | NSBInterpreter::~NSBInterpreter() 193 | { 194 | if (pDebuggerThread) 195 | pDebuggerThread->join(); 196 | 197 | delete pDebuggerThread; 198 | for (NSBContext* pContext : Threads) 199 | if (pContext->GetName() == "__main__" || pContext->GetName() == "UNK") 200 | delete pContext; 201 | } 202 | 203 | void NSBInterpreter::ExecuteLocalScript(const string& Filename) 204 | { 205 | ScriptFile* pScript = new ScriptFile(Filename, ScriptFile::NSS); 206 | for (const string& i : pScript->GetIncludes()) 207 | sResourceMgr->GetScriptFile(i); 208 | pContext->Call(pScript, "chapter.main"); 209 | } 210 | 211 | void NSBInterpreter::ExecuteScript(const string& Filename) 212 | { 213 | CallScript(Filename, "chapter.main"); 214 | } 215 | 216 | void NSBInterpreter::ExecuteScriptThread(const string& Filename) 217 | { 218 | NSBContext* pThread = new NSBContext("UNK"); 219 | AddThread(pThread); 220 | if (ScriptFile* pScript = sResourceMgr->GetScriptFile(Filename)) 221 | pThread->Call(pScript, "chapter.main"); 222 | } 223 | 224 | void NSBInterpreter::Run(int NumCommands) 225 | { 226 | for (int i = 0; i < NumCommands; ++i) 227 | RunCommand(); 228 | } 229 | 230 | void NSBInterpreter::RunCommand() 231 | { 232 | if (Threads.empty()) 233 | Exit(); 234 | 235 | if (!RunInterpreter) 236 | return; 237 | 238 | ThreadsModified = false; 239 | for (auto i = Threads.begin(); i != Threads.end(); ++i) 240 | { 241 | pContext = *i; 242 | pContext->TryWake(); 243 | 244 | while (pContext->IsActive() && !pContext->IsStarving() && !pContext->IsSleeping() && pContext->Advance() != MAGIC_CLEAR_PARAMS) 245 | { 246 | if (pContext->GetName() == "__main__") 247 | DebuggerTick(); 248 | 249 | if (pContext->GetMagic() < Builtins.size()) 250 | Call(pContext->GetMagic()); 251 | } 252 | 253 | ClearParams(); 254 | if (pContext->IsStarving()) 255 | { 256 | ObjectHolder.Delete(pContext->GetName()); 257 | RemoveThread(pContext); 258 | } 259 | 260 | if (ThreadsModified) 261 | break; 262 | } 263 | } 264 | 265 | void NSBInterpreter::Update(uint32_t Diff) 266 | { 267 | for (NSBContext* pContext : Threads) 268 | pContext->Update(Diff); 269 | } 270 | 271 | void NSBInterpreter::PushEvent(const SDL_Event& Event) 272 | { 273 | Events.push(Event); 274 | } 275 | 276 | void NSBInterpreter::HandleEvent(const SDL_Event& Event) 277 | { 278 | /* 279 | TODO: 280 | $SYSTEM_mousewheel_down 281 | $SYSTEM_mousewheel_up 282 | _onetime 283 | */ 284 | switch (Event.type) 285 | { 286 | case SDL_MOUSEBUTTONDOWN: 287 | ProcessButton(Event.button.button, "true"); 288 | for (auto pContext : Threads) 289 | pContext->OnClick(); 290 | break; 291 | case SDL_MOUSEBUTTONUP: 292 | ProcessButton(Event.button.button, "false"); 293 | break; 294 | case SDL_KEYDOWN: 295 | if (Event.key.keysym.sym == SDLK_F1) 296 | SkipHack = !SkipHack; 297 | 298 | ProcessKey(Event.key.keysym.sym, "true"); 299 | for (NSBShortcut& Shortcut : Shortcuts) 300 | if (Shortcut.Key == Event.key.keysym.sym) 301 | CallScriptThread(Shortcut.Script, "chapter.main"); 302 | break; 303 | case SDL_KEYUP: 304 | ProcessKey(Event.key.keysym.sym, "false"); 305 | break; 306 | } 307 | } 308 | 309 | void NSBInterpreter::ProcessButton(int button, const string& Val) 310 | { 311 | if (button == SDL_BUTTON_LEFT) 312 | SetString("$SYSTEM_l_button_down", Val); 313 | else if (button == SDL_BUTTON_RIGHT) 314 | SetString("$SYSTEM_r_button_down", Val); 315 | } 316 | 317 | void NSBInterpreter::ProcessKey(int Key, const string& Val) 318 | { 319 | static const map keydown = 320 | { 321 | { SDLK_RCTRL, "$SYSTEM_keydown_ctrl" }, 322 | { SDLK_KP_ENTER, "$SYSTEM_keydown_enter" }, 323 | { SDLK_RETURN, "$SYSTEM_keydown_enter" }, 324 | { SDLK_END, "$SYSTEM_keydown_end" }, 325 | { SDLK_ESCAPE, "$SYSTEM_keydown_esc" }, 326 | { SDLK_LEFT, "$SYSTEM_keydown_left" }, 327 | { SDLK_RIGHT, "$SYSTEM_keydown_right" }, 328 | { SDLK_DOWN, "$SYSTEM_keydown_up" }, 329 | { SDLK_UP, "$SYSTEM_keydown_down" }, 330 | { SDLK_ESCAPE, "$SYSTEM_keydown_esc" }, 331 | { SDLK_HOME, "$SYSTEM_keydown_home" }, 332 | { SDLK_PAGEDOWN, "$SYSTEM_keydown_pagedown" }, 333 | { SDLK_PAGEUP, "$SYSTEM_keydown_pageup" }, 334 | { SDLK_RSHIFT, "$SYSTEM_keydown_shift" }, 335 | { SDLK_SPACE, "$SYSTEM_keydown_space" }, 336 | { SDLK_TAB, "$SYSTEM_keydown_tab" } 337 | }; 338 | if (Key >= SDLK_a && Key <= SDLK_z) 339 | { 340 | char c = 'a' + Key - SDLK_a; 341 | string Identifier = "$SYSTEM_keydown_" + string(1, c); 342 | SetString(Identifier, Val); 343 | } 344 | auto it = keydown.find(Key); 345 | if (it != keydown.end()) 346 | SetString(it->second, Val); 347 | } 348 | 349 | void NSBInterpreter::FunctionDeclaration() 350 | { 351 | Params.Begin(pContext->GetNumParams() - 1); 352 | for (int i = 1; i < pContext->GetNumParams(); ++i) 353 | Assign_(i); 354 | } 355 | 356 | void NSBInterpreter::CallFunction() 357 | { 358 | CallFunction_(pContext, pContext->GetParam(0)); 359 | } 360 | 361 | void NSBInterpreter::CallScene() 362 | { 363 | CallScriptSymbol("scene."); 364 | } 365 | 366 | void NSBInterpreter::CallChapter() 367 | { 368 | CallScriptSymbol("chapter."); 369 | } 370 | 371 | void NSBInterpreter::CmpLogicalAnd() 372 | { 373 | BoolBinaryOp(logical_and()); 374 | } 375 | 376 | void NSBInterpreter::CmpLogicalOr() 377 | { 378 | BoolBinaryOp(logical_or()); 379 | } 380 | 381 | void NSBInterpreter::CmpGE() 382 | { 383 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 384 | FloatBinaryOp(greater_equal()); 385 | else 386 | IntBinaryOp(greater_equal()); 387 | } 388 | 389 | void NSBInterpreter::CmpGreater() 390 | { 391 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 392 | FloatBinaryOp(greater()); 393 | else 394 | IntBinaryOp(greater()); 395 | } 396 | 397 | void NSBInterpreter::CmpLess() 398 | { 399 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 400 | FloatBinaryOp(less()); 401 | else 402 | IntBinaryOp(less()); 403 | } 404 | 405 | void NSBInterpreter::CmpLE() 406 | { 407 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 408 | FloatBinaryOp(less_equal()); 409 | else 410 | IntBinaryOp(less_equal()); 411 | } 412 | 413 | void NSBInterpreter::CmpEqual() 414 | { 415 | Variable* pLhs = PopVar(); 416 | Variable* pRhs = PopVar(); 417 | 418 | bool Equal = false; 419 | if (pLhs->IsInt() && pRhs->IsInt()) 420 | Equal = pLhs->ToInt() == pRhs->ToInt(); 421 | else if (pLhs->IsString() && pRhs->IsString()) 422 | Equal = pLhs->ToString() == pRhs->ToString(); 423 | else if (pLhs->ToFloat() && pRhs->ToFloat()) 424 | Equal = pLhs->ToFloat() == pRhs->ToFloat(); 425 | 426 | Variable::Destroy(pLhs); 427 | Variable::Destroy(pRhs); 428 | PushVar(Variable::MakeInt(Equal)); 429 | } 430 | 431 | void NSBInterpreter::CmpNE() 432 | { 433 | CmpEqual(); 434 | Call(MAGIC_NOT_EXPRESSION); 435 | } 436 | 437 | void NSBInterpreter::NotExpression() 438 | { 439 | PushVar(Variable::MakeInt(!PopBool())); 440 | } 441 | 442 | void NSBInterpreter::AddExpression() 443 | { 444 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 445 | FloatBinaryOp(plus()); 446 | else 447 | { 448 | Variable* pLhs = PopVar(); 449 | Variable* pRhs = PopVar(); 450 | PushVar(Variable::Add(pLhs, pRhs)); 451 | } 452 | } 453 | 454 | void NSBInterpreter::SubExpression() 455 | { 456 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 457 | FloatBinaryOp(minus()); 458 | else 459 | IntBinaryOp(minus()); 460 | } 461 | 462 | void NSBInterpreter::MulExpression() 463 | { 464 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 465 | FloatBinaryOp(multiplies()); 466 | else 467 | IntBinaryOp(multiplies()); 468 | } 469 | 470 | void NSBInterpreter::DivExpression() 471 | { 472 | if (Params.Top()->IsFloat() || Params.TTop()->IsFloat()) 473 | FloatBinaryOp(divides()); 474 | else 475 | IntBinaryOp(divides()); 476 | } 477 | 478 | void NSBInterpreter::ModExpression() 479 | { 480 | IntBinaryOp(modulus()); 481 | } 482 | 483 | void NSBInterpreter::Increment() 484 | { 485 | if (Params.Top()->Name == "$SW_PHONE_SENDMAILNO") 486 | { 487 | Variable* pVar = PopVar(); 488 | int32_t Index = Nsb::ConstantToValue(pVar->ToString()); 489 | string Constant = Nsb::ValueToConstant(Index + 1); 490 | pVar->Set(Constant); 491 | PushVar(pVar); 492 | } 493 | else 494 | IntUnaryOp([](int32_t a) { return ++a; }); 495 | } 496 | 497 | void NSBInterpreter::Decrement() 498 | { 499 | IntUnaryOp([](int32_t a) { return --a; }); 500 | } 501 | 502 | void NSBInterpreter::Literal() 503 | { 504 | const string& Type = pContext->GetParam(0); 505 | const string& Val = pContext->GetParam(1); 506 | if (Type == "STRING") 507 | { 508 | if (Variable* pVar = VariableHolder.Read(Val)) 509 | PushVar(pVar); 510 | else 511 | PushString(Val); 512 | } 513 | else if (Type == "INT") 514 | PushInt(stoi(Val)); 515 | else if (Type == "FLOAT") 516 | PushFloat(stof(Val)); 517 | } 518 | 519 | void NSBInterpreter::Assign() 520 | { 521 | if (pContext->GetParam(0) == "__array_variable__") 522 | { 523 | Params.Begin(1); 524 | Variable* pVar = PopVar(); 525 | Variable* pLit = PopVar(); 526 | pVar->Set(pLit); 527 | Variable::Destroy(pLit); 528 | } 529 | else 530 | Assign_(0); 531 | } 532 | 533 | void NSBInterpreter::Get() 534 | { 535 | PushVar(GetVar(pContext->GetParam(0))); 536 | } 537 | 538 | void NSBInterpreter::ScopeBegin() 539 | { 540 | } 541 | 542 | void NSBInterpreter::ScopeEnd() 543 | { 544 | } 545 | 546 | void NSBInterpreter::Return() 547 | { 548 | pContext->Return(); 549 | } 550 | 551 | void NSBInterpreter::If() 552 | { 553 | if (!PopBool()) 554 | Jump(); 555 | } 556 | 557 | void NSBInterpreter::While() 558 | { 559 | pContext->PushBreak(); 560 | If(); 561 | } 562 | 563 | void NSBInterpreter::WhileEnd() 564 | { 565 | pContext->PopBreak(); 566 | } 567 | 568 | /* 569 | * Select an event for next iteration of event loop. (see: Case) 570 | * Valid events are: Mouse Up/Down/Wheel, Arrow Up/Down/Right/Left 571 | * */ 572 | void NSBInterpreter::Select() 573 | { 574 | pWindow->Select(true); 575 | if (SelectEvent()) 576 | pContext->PushBreak(); 577 | } 578 | 579 | void NSBInterpreter::SelectEnd() 580 | { 581 | SelectEvent(); 582 | } 583 | 584 | void NSBInterpreter::SelectBreakEnd() 585 | { 586 | pContext->PopBreak(); 587 | pWindow->Select(false); 588 | Events = queue(); 589 | } 590 | 591 | void NSBInterpreter::Break() 592 | { 593 | pContext->Break(); 594 | } 595 | 596 | void NSBInterpreter::Jump() 597 | { 598 | pContext->Jump(pContext->GetParam(0)); 599 | } 600 | 601 | Variable* NSBInterpreter::PopVar() 602 | { 603 | return Params.Pop(); 604 | } 605 | 606 | Texture* NSBInterpreter::PopTexture() 607 | { 608 | return Get(PopString()); 609 | } 610 | 611 | GLTexture* NSBInterpreter::PopGLTexture() 612 | { 613 | return Get(PopString()); 614 | } 615 | 616 | Playable* NSBInterpreter::PopPlayable() 617 | { 618 | return Get(PopString()); 619 | } 620 | 621 | Scrollbar* NSBInterpreter::PopScrollbar() 622 | { 623 | return Get(PopString()); 624 | } 625 | 626 | int32_t NSBInterpreter::PopInt() 627 | { 628 | Variable* pVar = PopVar(); 629 | int32_t Val = pVar->ToInt(); 630 | Variable::Destroy(pVar); 631 | return Val; 632 | } 633 | 634 | float NSBInterpreter::PopFloat() 635 | { 636 | Variable* pVar = PopVar(); 637 | float Val = pVar->ToFloat(); 638 | Variable::Destroy(pVar); 639 | return Val; 640 | } 641 | 642 | string NSBInterpreter::PopString() 643 | { 644 | Variable* pVar = PopVar(); 645 | string Val = pVar->ToString(); 646 | Variable::Destroy(pVar); 647 | return Val; 648 | } 649 | 650 | NSBPosition NSBInterpreter::PopPos() 651 | { 652 | const int32_t WIDTH = pWindow->WIDTH; 653 | const int32_t HEIGHT = pWindow->HEIGHT; 654 | static const size_t SPECIAL_POS_NUM = 19; 655 | static const PosFunc SpecialPosTable[SPECIAL_POS_NUM] = 656 | { 657 | [WIDTH] (int32_t x) { return WIDTH; }, // OutRight 658 | [] (int32_t x) { return -x; }, // OutLeft 659 | [] (int32_t y) { return -y; }, // OutTop 660 | [HEIGHT] (int32_t y) { return HEIGHT; }, // OutBottom 661 | 662 | [WIDTH] (int32_t x) { return WIDTH - x; }, // InRight 663 | [] (int32_t x) { return 0; }, // InLeft 664 | [] (int32_t y) { return 0; }, // InTop 665 | [HEIGHT] (int32_t y) { return HEIGHT - y; }, // InBottom 666 | 667 | [WIDTH] (int32_t x) { return WIDTH - (x / 2); }, // OnRight 668 | [] (int32_t x) { return -(x / 2); }, // OnLeft 669 | [] (int32_t y) { return -(y / 2); }, // OnTop 670 | [HEIGHT] (int32_t y) { return HEIGHT - (y / 2); }, // OnBottom 671 | 672 | [] (int32_t x) { return x; }, // Right 673 | [] (int32_t x) { return 0; }, // Left 674 | [] (int32_t y) { return 0; }, // Top 675 | [] (int32_t y) { return y; }, // Bottom 676 | 677 | [WIDTH] (int32_t x) { return (WIDTH - x) / 2; }, // Center 678 | [HEIGHT] (int32_t y) { return (HEIGHT - y) / 2; }, // Middle 679 | [] (int32_t xy) { return numeric_limits::max(); } // Auto 680 | }; 681 | static const string SpecialPos[SPECIAL_POS_NUM] = 682 | { 683 | "outright", "outleft", "outtop", "outbottom", 684 | "inright", "inleft", "intop", "inbottom", 685 | "onright", "onleft", "ontop", "onbottom", 686 | "right", "left", "top", "bottom", 687 | "center", "middle", "auto" 688 | }; 689 | 690 | NSBPosition Position; 691 | Variable* pVar = PopVar(); 692 | Position.Relative = pVar->Relative; 693 | if (pVar->IsInt()) 694 | { 695 | int32_t Val = pVar->ToInt(); 696 | Position.Func = [Val] (int32_t) { return Val; }; 697 | } 698 | else 699 | { 700 | string Str = pVar->ToString(); 701 | transform(Str.begin(), Str.end(), Str.begin(), ::tolower); 702 | size_t i = -1; 703 | while (++i < SPECIAL_POS_NUM) 704 | if (Str == SpecialPos[i]) 705 | Position.Func = SpecialPosTable[i]; 706 | } 707 | Variable::Destroy(pVar); 708 | return Position; 709 | } 710 | 711 | NSBPosition NSBInterpreter::PopRelative() 712 | { 713 | NSBPosition Position; 714 | Variable* pVar = PopVar(); 715 | Position.Relative = pVar->Relative; 716 | int32_t Val = pVar->ToInt(); 717 | Position.Func = [Val] (int32_t) { return Val; }; 718 | Variable::Destroy(pVar); 719 | return Position; 720 | } 721 | 722 | uint32_t NSBInterpreter::PopColor() 723 | { 724 | uint32_t Color = 0; 725 | Variable* pVar = PopVar(); 726 | if (pVar->IsString()) 727 | { 728 | string Str = boost::algorithm::to_lower_copy(pVar->ToString()); 729 | if (Nsb::IsValidConstant(Str)) 730 | Color = Nsb::ConstantToValue(Str); 731 | else 732 | { 733 | size_t i = Str.find_first_of("0123456789abcdef"); 734 | if (i != Str.npos && Str.size() - i >= 6) 735 | Color = stoi(Str.substr(i, 6), nullptr, 16) | (0xFF << 24); 736 | } 737 | } 738 | else 739 | Color = stoi(to_string(pVar->ToInt()), nullptr, 16) | (0xFF << 24); 740 | 741 | Variable::Destroy(pVar); 742 | return Color; 743 | } 744 | 745 | int32_t NSBInterpreter::PopRequest() 746 | { 747 | return Nsb::ConstantToValue(PopString()); 748 | } 749 | 750 | int32_t NSBInterpreter::PopTone() 751 | { 752 | return Nsb::ConstantToValue(PopString()); 753 | } 754 | 755 | int32_t NSBInterpreter::PopEffect() 756 | { 757 | return Nsb::ConstantToValue(PopString()); 758 | } 759 | 760 | int32_t NSBInterpreter::PopShade() 761 | { 762 | return Nsb::ConstantToValue(PopString()); 763 | } 764 | 765 | int32_t NSBInterpreter::PopTempo() 766 | { 767 | return Nsb::ConstantToValue(PopString()); 768 | } 769 | 770 | bool NSBInterpreter::PopBool() 771 | { 772 | Variable* pVar = PopVar(); 773 | bool ret = ToBool(pVar); 774 | Variable::Destroy(pVar); 775 | return ret; 776 | } 777 | 778 | string NSBInterpreter::PopSave() 779 | { 780 | boost::format Fmt("%s/%04d.npf"); 781 | Fmt % GetString("#SYSTEM_save_path"); 782 | Fmt % PopInt(); 783 | return Fmt.str(); 784 | } 785 | 786 | void NSBInterpreter::PushFloat(float Float) 787 | { 788 | PushVar(Variable::MakeFloat(Float)); 789 | } 790 | 791 | void NSBInterpreter::PushInt(int32_t Int) 792 | { 793 | PushVar(Variable::MakeInt(Int)); 794 | } 795 | 796 | void NSBInterpreter::PushString(const string& Str) 797 | { 798 | PushVar(Variable::MakeString(Str)); 799 | } 800 | 801 | void NSBInterpreter::PushVar(Variable* pVar) 802 | { 803 | Params.Push(pVar); 804 | } 805 | 806 | void NSBInterpreter::Assign_(int Index) 807 | { 808 | SetVar(pContext->GetParam(Index), PopVar()); 809 | } 810 | 811 | void NSBInterpreter::IntUnaryOp(function Func) 812 | { 813 | PushVar(PopVar()->IntUnaryOp(Func)); 814 | } 815 | 816 | void NSBInterpreter::IntBinaryOp(function Func) 817 | { 818 | int32_t lhs = PopInt(); 819 | int32_t rhs = PopInt(); 820 | PushInt(Func(lhs, rhs)); 821 | } 822 | 823 | void NSBInterpreter::FloatBinaryOp(function Func) 824 | { 825 | float lhs = PopFloat(); 826 | float rhs = PopFloat(); 827 | PushFloat(Func(lhs, rhs)); 828 | } 829 | 830 | void NSBInterpreter::BoolBinaryOp(function Func) 831 | { 832 | bool lhs = PopBool(); 833 | bool rhs = PopBool(); 834 | PushInt(Func(lhs, rhs)); 835 | } 836 | 837 | void NSBInterpreter::CallFunction_(NSBContext* pThread, const string& Symbol) 838 | { 839 | if (!pThread->Call(pContext->GetScript(), string("function.") + Symbol)) 840 | NSB_ERROR("Failed to call function", Symbol); 841 | } 842 | 843 | void NSBInterpreter::CallScriptSymbol(const string& Prefix) 844 | { 845 | string ScriptName = GetString(pContext->GetParam(0)), Symbol; 846 | size_t i = ScriptName.find("->"); 847 | if (i != string::npos) 848 | { 849 | Symbol = ScriptName.substr(i + 2); 850 | ScriptName.erase(i); 851 | } 852 | else 853 | Symbol = "main"; 854 | CallScript(ScriptName == "@" ? pContext->GetScriptName() : ScriptName, Prefix + Symbol); 855 | } 856 | 857 | void NSBInterpreter::CallScript(const string& Filename, const string& Symbol) 858 | { 859 | if (ScriptFile* pScript = sResourceMgr->GetScriptFile(Filename)) 860 | pContext->Call(pScript, Symbol); 861 | } 862 | 863 | void NSBInterpreter::CallScriptThread(const string& Filename, const string& Symbol) 864 | { 865 | NSBContext* pThread = new NSBContext("UNK"); 866 | AddThread(pThread); 867 | if (ScriptFile* pScript = sResourceMgr->GetScriptFile(Filename)) 868 | pThread->Call(pScript, Symbol); 869 | } 870 | 871 | void NSBInterpreter::Call(uint16_t Magic) 872 | { 873 | uint8_t NumParams = Builtins[Magic].NumParams; 874 | Params.Begin(NumParams == NSB_VARARGS ? pContext->GetNumParams() : NumParams); 875 | 876 | if (Builtins[Magic].Func) 877 | (this->*Builtins[Magic].Func)(); 878 | } 879 | 880 | bool NSBInterpreter::SelectEvent() 881 | { 882 | if (!Events.empty()) 883 | { 884 | Event = Events.front(); 885 | Events.pop(); 886 | return true; 887 | } 888 | else 889 | { 890 | pContext->Rewind(); 891 | pContext->Wait(20); 892 | return false; 893 | } 894 | } 895 | 896 | void NSBInterpreter::AddThread(NSBContext* pThread) 897 | { 898 | pThread->Start(); 899 | Threads.push_back(pThread); 900 | ThreadsModified = true; 901 | } 902 | 903 | void NSBInterpreter::RemoveThread(NSBContext* pThread) 904 | { 905 | Threads.remove(pThread); 906 | ThreadsModified = true; 907 | } 908 | 909 | int32_t NSBInterpreter::GetInt(const string& Name) 910 | { 911 | return GetVar(Name)->ToInt(); 912 | } 913 | 914 | bool NSBInterpreter::GetBool(const string& Name) 915 | { 916 | return ToBool(GetVar(Name)); 917 | } 918 | 919 | string NSBInterpreter::GetString(const string& Name) 920 | { 921 | if (Name[0] != '$' && Name[0] != '#') 922 | return Name; 923 | return GetVar(Name)->ToString(); 924 | } 925 | 926 | bool NSBInterpreter::ToBool(Variable* pVar) 927 | { 928 | if (pVar->IsString()) 929 | { 930 | int32_t Val = Nsb::ConstantToValue(pVar->ToString()); 931 | if (Val != -1) 932 | return static_cast(Val); 933 | } 934 | return static_cast(pVar->ToInt()); 935 | } 936 | 937 | Variable* NSBInterpreter::GetVar(const string& Name) 938 | { 939 | if (Variable* pVar = VariableHolder.Read(Name)) 940 | return pVar; 941 | 942 | Variable* pVar = Variable::MakeNull(Name); 943 | VariableHolder.Write(Name, pVar); 944 | return pVar; 945 | } 946 | 947 | Object* NSBInterpreter::GetObject(const string& Name) 948 | { 949 | return ObjectHolder.Read(Name); 950 | } 951 | 952 | void NSBInterpreter::OnVariableChanged(const string& Name) 953 | { 954 | if (Name == "#SYSTEM_window_full") 955 | pWindow->SetFullscreen(GetBool("#SYSTEM_window_full") ? SDL_WINDOW_FULLSCREEN : 0); 956 | } 957 | 958 | void NSBInterpreter::SetVar(const string& Name, Variable* pVar) 959 | { 960 | GetVar(Name)->Set(pVar); 961 | OnVariableChanged(Name); 962 | Variable::Destroy(pVar); 963 | } 964 | 965 | void NSBInterpreter::SetInt(const string& Name, int32_t Val) 966 | { 967 | SetVar(Name, Variable::MakeInt(Val)); 968 | } 969 | 970 | void NSBInterpreter::SetString(const string& Name, const string& Val) 971 | { 972 | SetVar(Name, Variable::MakeString(Val)); 973 | } 974 | 975 | void NSBInterpreter::AddAssign() 976 | { 977 | Variable* pVar = GetVar(pContext->GetParam(0)); 978 | Variable* pTemp = Variable::Add(pVar, PopVar()); 979 | pVar->Set(pTemp); 980 | Variable::Destroy(pTemp); 981 | } 982 | 983 | void NSBInterpreter::SubAssign() 984 | { 985 | Variable* pVar = GetVar(pContext->GetParam(0)); 986 | Variable* pTemp = Variable::MakeInt(pVar->ToInt() - PopInt()); 987 | pVar->Set(pTemp); 988 | Variable::Destroy(pTemp); 989 | } 990 | 991 | void NSBInterpreter::ModAssign() 992 | { 993 | Variable* pVar = GetVar(pContext->GetParam(0)); 994 | Variable* pTemp = Variable::MakeInt(pVar->ToInt() % PopInt()); 995 | pVar->Set(pTemp); 996 | Variable::Destroy(pTemp); 997 | } 998 | 999 | void NSBInterpreter::WriteFile() 1000 | { 1001 | string Filename = PopString(); 1002 | string Data = NpaFile::FromUtf8(PopString()); 1003 | uint32_t Size = Data.size(); 1004 | fs::WriteFileDirectory(Filename, NpaFile::Encrypt(&Data[0], Size), Size); 1005 | } 1006 | 1007 | void NSBInterpreter::ReadFile() 1008 | { 1009 | string Filename = PopString(); 1010 | uint32_t Size; 1011 | char* pData = fs::ReadFile(Filename, Size); 1012 | NpaFile::Decrypt(pData, Size); 1013 | PushString(NpaFile::ToUtf8(pData, Size)); 1014 | delete[] pData; 1015 | } 1016 | 1017 | void NSBInterpreter::CreateTexture() 1018 | { 1019 | string Handle = PopString(); 1020 | int32_t Priority = PopInt(); 1021 | NSBPosition X = PopPos(); 1022 | NSBPosition Y = PopPos(); 1023 | string Source = PopString(); 1024 | 1025 | Texture* pTexture = new Texture; 1026 | if (Source == "VIDEO") 1027 | ; 1028 | else if (Source == "SCREEN") 1029 | pTexture->CreateFromScreen(pWindow); 1030 | else if (Source.size() < 4 || Source[Source.size() - 4] != '.') 1031 | { 1032 | if (GLTexture* pSource = Get(Source)) 1033 | pTexture->CreateFromGLTexture(pSource); 1034 | else if (Image* pSource = Get(Source)) 1035 | pTexture->CreateFromImage(pSource); 1036 | } 1037 | else 1038 | pTexture->CreateFromFile(Source); 1039 | 1040 | pTexture->SetVertex(pTexture->GetWidth() / 2, pTexture->GetHeight() / 2); 1041 | pTexture->Move(X(pTexture->GetWidth()), Y(pTexture->GetHeight())); 1042 | pTexture->SetPriority(Priority); 1043 | 1044 | pWindow->AddTexture(pTexture); 1045 | ObjectHolder.Write(Handle, pTexture); 1046 | } 1047 | 1048 | void NSBInterpreter::ImageHorizon() 1049 | { 1050 | Texture* pTexture = PopTexture(); 1051 | PushInt(pTexture ? pTexture->GetWidth() : 0); 1052 | } 1053 | 1054 | void NSBInterpreter::ImageVertical() 1055 | { 1056 | Texture* pTexture = PopTexture(); 1057 | PushInt(pTexture ? pTexture->GetHeight() : 0); 1058 | } 1059 | 1060 | void NSBInterpreter::Time() 1061 | { 1062 | PushInt(time(0)); 1063 | } 1064 | 1065 | void NSBInterpreter::StrStr() 1066 | { 1067 | string Haystack = PopString(); 1068 | string Needle = PopString(); 1069 | PushInt(Haystack.find(Needle) + 1); 1070 | } 1071 | 1072 | void NSBInterpreter::Exit() 1073 | { 1074 | // TODO: save # variables in 0000.npf 1075 | pWindow->Exit(); 1076 | } 1077 | 1078 | void NSBInterpreter::CursorPosition() 1079 | { 1080 | int32_t X, Y; 1081 | SDL_PumpEvents(); 1082 | SDL_GetMouseState(&X, &Y); 1083 | SetInt(PopString(), X); 1084 | SetInt(PopString(), Y); 1085 | } 1086 | 1087 | void NSBInterpreter::MoveCursor() 1088 | { 1089 | int32_t X = PopInt(); 1090 | int32_t Y = PopInt(); 1091 | pWindow->MoveCursor(X, Y); 1092 | } 1093 | 1094 | void NSBInterpreter::Position() 1095 | { 1096 | Texture* pTexture = PopTexture(); 1097 | SetInt(pContext->GetParam(1), pTexture->GetX()); 1098 | SetInt(pContext->GetParam(2), pTexture->GetY()); 1099 | } 1100 | 1101 | void NSBInterpreter::Wait() 1102 | { 1103 | pContext->Wait(PopInt()); 1104 | } 1105 | 1106 | void NSBInterpreter::WaitKey() 1107 | { 1108 | pContext->WaitKey(pContext->GetNumParams() == 1 ? PopInt() : -1); 1109 | } 1110 | 1111 | void NSBInterpreter::NegaExpression() 1112 | { 1113 | IntUnaryOp(negate()); 1114 | } 1115 | 1116 | void NSBInterpreter::System() 1117 | { 1118 | static const string OpenStr = "OPEN:"; 1119 | string Command = PopString(); 1120 | string Parameters = PopString(); 1121 | string Directory = PopString(); 1122 | if (Command.substr(0, OpenStr.size()) != OpenStr) 1123 | return; 1124 | 1125 | Command = Command.substr(OpenStr.size()); 1126 | 1127 | if (fork() == 0) 1128 | execlp("/usr/bin/xdg-open", "/usr/bin/xdg-open", Command.c_str(), NULL); 1129 | } 1130 | 1131 | void NSBInterpreter::String() 1132 | { 1133 | boost::format Fmt(PopString()); 1134 | for (int i = 1; i < pContext->GetNumParams(); ++i) 1135 | { 1136 | Variable* pVar = PopVar(); 1137 | if (pVar->IsInt()) 1138 | Fmt % pVar->ToInt(); 1139 | else if (pVar->IsString()) 1140 | Fmt % pVar->ToString(); 1141 | else if (pVar->IsFloat()) 1142 | Fmt % pVar->ToFloat(); 1143 | Variable::Destroy(pVar); 1144 | } 1145 | PushString(Fmt.str()); 1146 | } 1147 | 1148 | void NSBInterpreter::VariableValue() 1149 | { 1150 | string Type = PopString(); 1151 | string Name = PopString(); 1152 | 1153 | // Check if it's array index. Not sure about this... 1154 | if (Name.size() > 3 && Name[Name.size() - 3] == '[' && Name.back() == ']' && isdigit(Name[Name.size() - 2])) 1155 | PushVar(GetVar(Name.substr(0, Name.size() - 3) + "/" + to_string(Name[Name.size() - 2]))); 1156 | else if (pContext->GetNumParams() == 3) 1157 | SetVar(Type + Name, PopVar()); 1158 | else if (pContext->GetNumParams() == 2) 1159 | PushVar(GetVar(Type + Name)); 1160 | else 1161 | assert(false && "This will trigger when we get new season of Haruhi"); 1162 | } 1163 | 1164 | void NSBInterpreter::CreateProcess() 1165 | { 1166 | string Handle = PopString(); 1167 | /*int32_t unk1 = */PopInt(); 1168 | /*int32_t unk2 = */PopInt(); 1169 | /*int32_t unk3 = */PopInt(); 1170 | string Symbol = PopString(); 1171 | 1172 | NSBContext* pThread = new NSBContext(Handle); 1173 | CallFunction_(pThread, Symbol); 1174 | AddThread(pThread); 1175 | ObjectHolder.Write(Handle, pThread); 1176 | } 1177 | 1178 | void NSBInterpreter::Count() 1179 | { 1180 | Variable* pArr = PopVar(); 1181 | int SCount = count(pArr->Name.begin(), pArr->Name.end(), '/') + 1; 1182 | int32_t Size = 0; 1183 | for (auto& i : VariableHolder.Cache) 1184 | { 1185 | string Prefix = i.first.substr(0, pArr->Name.size()); 1186 | int Count = count(i.first.begin(), i.first.end(), '/'); 1187 | if (Prefix == pArr->Name && SCount == Count) 1188 | Size++; 1189 | } 1190 | PushInt(Size); 1191 | } 1192 | 1193 | void NSBInterpreter::Array() 1194 | { 1195 | Variable* pArr = PopVar(); 1196 | if (!pArr) 1197 | { 1198 | pArr = Variable::MakeNull(pContext->GetParam(0)); 1199 | VariableHolder.Write(pContext->GetParam(0), pArr); 1200 | } 1201 | for (int i = 1; i < pContext->GetNumParams(); ++i) 1202 | { 1203 | string Name = pArr->Name + "/" + to_string(i - 1); 1204 | Variable* pVar = Variable::MakeCopy(PopVar(), Name); 1205 | VariableHolder.Write(Name, pVar); 1206 | } 1207 | } 1208 | 1209 | void NSBInterpreter::SubScript() 1210 | { 1211 | Variable* pArr = GetVar(pContext->GetParam(0)); 1212 | int32_t Depth = stoi(pContext->GetParam(1)); 1213 | Params.Begin(Depth); 1214 | while (Depth --> 0) 1215 | { 1216 | Variable* pVar = PopVar(); 1217 | int Index = pVar->IsInt() ? pVar->ToInt() : pArr->Assoc[pVar->ToString()]; 1218 | pArr = GetVar(pArr->Name + "/" + to_string(Index)); 1219 | Variable::Destroy(pVar); 1220 | } 1221 | PushVar(pArr); 1222 | } 1223 | 1224 | void NSBInterpreter::AssocArray() 1225 | { 1226 | Variable* pArr = PopVar(); 1227 | for (int i = 1; i < pContext->GetNumParams(); ++i) 1228 | pArr->Assoc[PopString()] = i - 1; 1229 | } 1230 | 1231 | void NSBInterpreter::ModuleFileName() 1232 | { 1233 | string Name = pContext->GetScriptName(); 1234 | PushString(Name.substr(4, Name.size() - 8)); // Remove nss/ and .nsb 1235 | } 1236 | 1237 | void NSBInterpreter::Request() 1238 | { 1239 | string Handle = PopString(); 1240 | int32_t Request = PopRequest(); 1241 | 1242 | ObjectHolder.Execute(Handle, [Request] (Object** ppObject) 1243 | { 1244 | if (Object* pObject = *ppObject) 1245 | pObject->Request(Request); 1246 | }); 1247 | } 1248 | 1249 | void NSBInterpreter::SetVertex() 1250 | { 1251 | Texture* pTexture = PopTexture(); 1252 | NSBPosition X = PopPos(); 1253 | NSBPosition Y = PopPos(); 1254 | 1255 | if (pTexture) 1256 | pTexture->SetVertex(X(pTexture->GetWidth(), pTexture->GetOX()), Y(pTexture->GetHeight(), pTexture->GetOY())); 1257 | } 1258 | 1259 | void NSBInterpreter::Zoom() 1260 | { 1261 | string Handle = PopString(); 1262 | int32_t Time = PopInt(); 1263 | NSBPosition XScale = PopRelative(); 1264 | NSBPosition YScale = PopRelative(); 1265 | int32_t Tempo = PopTempo(); 1266 | bool Wait = PopBool(); 1267 | 1268 | ObjectHolder.Execute(Handle, [&] (Object** ppObject) 1269 | { 1270 | if (Texture* pTexture = dynamic_cast(*ppObject)) 1271 | pTexture->Zoom(Time, XScale(0, pTexture->GetXScale()), YScale(0, pTexture->GetYScale()), Tempo); 1272 | }); 1273 | 1274 | if (Wait) 1275 | pContext->Wait(Time); 1276 | } 1277 | 1278 | void NSBInterpreter::Move() 1279 | { 1280 | string Handle = PopString(); 1281 | int32_t Time = PopInt(); 1282 | NSBPosition X = PopPos(); 1283 | NSBPosition Y = PopPos(); 1284 | int32_t Tempo = PopTempo(); 1285 | bool Wait = PopBool(); 1286 | 1287 | ObjectHolder.Execute(Handle, [&] (Object** ppObject) 1288 | { 1289 | if (Texture* pTexture = dynamic_cast(*ppObject)) 1290 | pTexture->Move(X(pTexture->GetWidth(), pTexture->GetMX()), Y(pTexture->GetHeight(), pTexture->GetMY()), Time, Tempo); 1291 | }); 1292 | 1293 | if (Wait) 1294 | pContext->Wait(Time); 1295 | } 1296 | 1297 | void NSBInterpreter::SetShade() 1298 | { 1299 | if (Texture* pTexture = PopTexture()) 1300 | pTexture->SetShade(PopShade()); 1301 | } 1302 | 1303 | void NSBInterpreter::DrawToTexture() 1304 | { 1305 | GLTexture* pTexture = PopGLTexture(); 1306 | int32_t X = PopInt(); 1307 | int32_t Y = PopInt(); 1308 | string Filename = PopString(); 1309 | 1310 | if (pTexture) 1311 | pTexture->Draw(X, Y, Filename); 1312 | } 1313 | 1314 | void NSBInterpreter::CreateRenderTexture() 1315 | { 1316 | string Handle = PopString(); 1317 | int32_t Width = PopInt(); 1318 | int32_t Height = PopInt(); 1319 | uint32_t Color = PopColor(); 1320 | 1321 | GLTexture* pTexture = new GLTexture; 1322 | pTexture->CreateFromColor(Width, Height, Color); 1323 | ObjectHolder.Write(Handle, pTexture); 1324 | } 1325 | 1326 | void NSBInterpreter::DrawTransition() 1327 | { 1328 | Texture* pTexture = PopTexture(); 1329 | int32_t Time = PopInt(); 1330 | int32_t Start = PopInt(); 1331 | int32_t End = PopInt(); 1332 | int32_t Boundary = PopInt(); 1333 | int32_t Tempo = PopTempo(); 1334 | string Filename = PopString(); 1335 | bool Wait = PopBool(); 1336 | 1337 | if (pTexture) 1338 | pTexture->DrawTransition(Time, Start, End, Boundary, Tempo, Filename); 1339 | 1340 | if (Wait) 1341 | pContext->Wait(Time); 1342 | } 1343 | 1344 | void NSBInterpreter::CreateColor() 1345 | { 1346 | string Handle = PopString(); 1347 | int32_t Priority = PopInt(); 1348 | NSBPosition X = PopPos(); 1349 | NSBPosition Y = PopPos(); 1350 | int32_t Width = PopInt(); 1351 | int32_t Height = PopInt(); 1352 | uint32_t Color = PopColor(); 1353 | 1354 | Texture* pTexture = new Texture; 1355 | pTexture->CreateFromColor(Width, Height, Color); 1356 | pTexture->SetVertex(Width / 2, Height / 2); 1357 | pTexture->Move(X(Width), Y(Height)); 1358 | pTexture->SetPriority(Priority); 1359 | 1360 | pWindow->AddTexture(pTexture); 1361 | ObjectHolder.Write(Handle, pTexture); 1362 | } 1363 | 1364 | void NSBInterpreter::LoadImage() 1365 | { 1366 | string Handle = PopString(); 1367 | string Filename = PopString(); 1368 | 1369 | Image* pImage = new Image; 1370 | if (Filename == "SCREEN") 1371 | pImage->LoadScreen(pWindow); 1372 | else 1373 | pImage->LoadImage(Filename); 1374 | ObjectHolder.Write(Handle, pImage); 1375 | } 1376 | 1377 | void NSBInterpreter::Fade() 1378 | { 1379 | string Handle = PopString(); 1380 | int32_t Time = PopInt(); 1381 | int32_t Opacity = PopInt(); 1382 | int32_t Tempo = PopTempo(); 1383 | bool Wait = PopBool(); 1384 | 1385 | ObjectHolder.Execute(Handle, [Time, Opacity, Tempo] (Object** ppObject) 1386 | { 1387 | if (Texture* pTexture = dynamic_cast(*ppObject)) 1388 | pTexture->Fade(Time, Opacity, Tempo); 1389 | }); 1390 | 1391 | if (Wait) 1392 | pContext->Wait(Time); 1393 | } 1394 | 1395 | void NSBInterpreter::Delete() 1396 | { 1397 | string Handle = PopString(); 1398 | 1399 | ObjectHolder.Execute(Handle, [this] (Object** ppObject) 1400 | { 1401 | if (Object* pObject = *ppObject) 1402 | { 1403 | if (pObject->Lock) 1404 | return; 1405 | 1406 | if (NSBContext* pThread = dynamic_cast(pObject)) 1407 | RemoveThread(pThread); 1408 | 1409 | delete pObject; 1410 | *ppObject = nullptr; 1411 | } 1412 | }); 1413 | } 1414 | 1415 | void NSBInterpreter::ClearParams() 1416 | { 1417 | Params.Reset(); 1418 | } 1419 | 1420 | void NSBInterpreter::SetLoop() 1421 | { 1422 | if (Playable* pPlayable = PopPlayable()) 1423 | pPlayable->SetLoop(PopBool()); 1424 | } 1425 | 1426 | void NSBInterpreter::SetVolume() 1427 | { 1428 | string Handle = PopString(); 1429 | int32_t Time = PopInt(); 1430 | int32_t Volume = PopInt(); 1431 | int32_t Tempo = PopTempo(); 1432 | 1433 | ObjectHolder.Execute(Handle, [Time, Volume, Tempo] (Object** ppObject) 1434 | { 1435 | if (Playable* pPlayable = dynamic_cast(*ppObject)) 1436 | pPlayable->SetVolume(Time, Volume, Tempo); 1437 | }); 1438 | } 1439 | 1440 | void NSBInterpreter::SetLoopPoint() 1441 | { 1442 | string Handle = PopString(); 1443 | int32_t Begin = PopInt(); 1444 | int32_t End = PopInt(); 1445 | 1446 | if (Playable* pPlayable = Get(Handle)) 1447 | pPlayable->SetLoopPoint(Begin, End); 1448 | } 1449 | 1450 | void NSBInterpreter::CreateSound() 1451 | { 1452 | string Handle = PopString(); 1453 | string Type = PopString(); 1454 | string File = PopString(); 1455 | 1456 | if (File.substr(File.size() - 4) != ".ogg") 1457 | File += ".ogg"; 1458 | 1459 | Resource Res = sResourceMgr->GetResource(File); 1460 | if (!Res.IsValid()) 1461 | return; 1462 | 1463 | int32_t Volume = 0; 1464 | if (Type == "BGM") 1465 | Volume = GetInt("#SYSTEM_sound_volume_bgm"); 1466 | else if (Type == "SE") 1467 | Volume = GetInt("#SYSTEM_sound_volume_se"); 1468 | else if (Type == "VOICE") 1469 | Volume = GetInt("#SYSTEM_sound_volume_voice"); 1470 | else 1471 | return; 1472 | 1473 | Playable* pPlayable = new Playable(Res); 1474 | pPlayable->SetVolume(0, Volume, -1); 1475 | ObjectHolder.Write(Handle, pPlayable); 1476 | } 1477 | 1478 | void NSBInterpreter::RemainTime() 1479 | { 1480 | Playable* pPlayable = PopPlayable(); 1481 | PushInt(pPlayable ? pPlayable->RemainTime() : 0); 1482 | } 1483 | 1484 | void NSBInterpreter::CreateMovie() 1485 | { 1486 | string Handle = PopString(); 1487 | int32_t Priority = PopInt(); 1488 | /*NSBPosition X = */PopPos(); 1489 | /*NSBPosition Y = */PopPos(); 1490 | bool Loop = PopBool(); 1491 | bool Alpha = PopBool(); 1492 | string File = PopString(); 1493 | bool Audio = PopBool(); 1494 | 1495 | Movie* pMovie = new Movie(File, pWindow, Priority, Alpha, Audio); 1496 | pMovie->SetLoop(Loop); 1497 | pWindow->AddTexture(pMovie); 1498 | ObjectHolder.Write(Handle, pMovie); 1499 | } 1500 | 1501 | void NSBInterpreter::DurationTime() 1502 | { 1503 | Playable* pPlayable = PopPlayable(); 1504 | PushInt(pPlayable ? pPlayable->DurationTime() : 0); 1505 | } 1506 | 1507 | void NSBInterpreter::SetFrequency() 1508 | { 1509 | string Handle = PopString(); 1510 | int32_t Time = PopInt(); 1511 | int32_t Frequency = PopInt(); 1512 | int32_t Tempo = PopTempo(); 1513 | 1514 | if (Playable* pPlayable = Get(Handle)) 1515 | pPlayable->SetFrequency(Time, Frequency, Tempo); 1516 | } 1517 | 1518 | void NSBInterpreter::SetPan() 1519 | { 1520 | string Handle = PopString(); 1521 | int32_t Time = PopInt(); 1522 | int32_t Pan = PopInt(); 1523 | int32_t Tempo = PopTempo(); 1524 | 1525 | if (Playable* pPlayable = Get(Handle)) 1526 | pPlayable->SetPan(Time, Pan, Tempo); 1527 | } 1528 | 1529 | void NSBInterpreter::SetAlias() 1530 | { 1531 | string Handle = PopString(); 1532 | string Alias = PopString(); 1533 | ObjectHolder.WriteAlias(Handle, Alias); 1534 | } 1535 | 1536 | void NSBInterpreter::CreateName() 1537 | { 1538 | ObjectHolder.Write(PopString(), new Name); 1539 | } 1540 | 1541 | void NSBInterpreter::CreateWindow() 1542 | { 1543 | string Handle = PopString(); 1544 | 1545 | Window_t* pWindow = new Window_t; 1546 | pWindow->Priority = PopInt(); 1547 | pWindow->X = PopInt(); 1548 | pWindow->Y = PopInt(); 1549 | pWindow->Width = PopInt(); 1550 | pWindow->Height = PopInt(); 1551 | /*bool unk = */PopBool(); 1552 | 1553 | ObjectHolder.Write(Handle, pWindow); 1554 | } 1555 | 1556 | void NSBInterpreter::CreateChoice() 1557 | { 1558 | ObjectHolder.Write(PopString(), new Choice); 1559 | 1560 | for (int i = 1; i < pContext->GetNumParams(); ++i) 1561 | PopInt(); 1562 | } 1563 | 1564 | /* 1565 | * Check if selected (see: Select) event satisfies a case. 1566 | * In practise, this checks if button was clicked, and if so, jumps to 1567 | * beginning of case code block. Otherwise, jump over the case block. 1568 | * After the code block is executed, no other cases will be checked. 1569 | * 1570 | * NOTE: For unknown reason, MAGIC_CASE's last parameter is label which 1571 | * points to beginning of the case, even though case code block always 1572 | * begins on the next line of code. 1573 | * */ 1574 | void NSBInterpreter::Case() 1575 | { 1576 | bool Choose = false; 1577 | if (Choice* pChoice = Get(pContext->GetParam(0))) 1578 | { 1579 | Choose = pChoice->IsSelected(Event); 1580 | pChoice->Reset(); 1581 | } 1582 | 1583 | pContext->Jump(Choose ? pContext->GetParam(2) : pContext->GetParam(1)); 1584 | } 1585 | 1586 | void NSBInterpreter::CaseEnd() 1587 | { 1588 | } 1589 | 1590 | void NSBInterpreter::SetNextFocus() 1591 | { 1592 | Choice* pFirst = Get(PopString()); 1593 | Choice* pSecond = Get(PopString()); 1594 | string Key = PopString(); 1595 | 1596 | if (pFirst && pSecond) 1597 | pFirst->SetNextFocus(pSecond, Key); 1598 | } 1599 | 1600 | void NSBInterpreter::PassageTime() 1601 | { 1602 | Playable* pPlayable = PopPlayable(); 1603 | PushInt(pPlayable ? pPlayable->PassageTime() : 0); 1604 | } 1605 | 1606 | void NSBInterpreter::ParseText() 1607 | { 1608 | string Handle = pContext->GetParam(0); 1609 | string Box = pContext->GetParam(1); 1610 | string XML = pContext->GetParam(2); 1611 | 1612 | ObjectHolder.Delete(GetVar("$SYSTEM_present_text")->ToString()); 1613 | 1614 | Text* pText = new Text; 1615 | pText->CreateFromXML(XML); 1616 | Handle = Box + "/" + Handle; 1617 | SetString("$SYSTEM_present_text", Handle); 1618 | ObjectHolder.Write(Handle, pText); 1619 | } 1620 | 1621 | void NSBInterpreter::LoadText() 1622 | { 1623 | /*string unk = */PopString(); 1624 | /*string BoxHandle = */PopString(); 1625 | string TextHandle = PopString(); 1626 | int32_t Width = PopInt(); 1627 | /*int32_t Height = */PopInt(); 1628 | /*int32_t LetterSpacing = */PopInt(); 1629 | /*int32_t LineSpacing = */PopInt(); 1630 | 1631 | if (Text* pText = Get(TextHandle)) 1632 | { 1633 | pText->SetColor(Text::dInColor); 1634 | pText->SetCharacterSize(Text::dSize); 1635 | pText->SetPriority(0xFFFF); // [HACK] 1636 | pText->SetWrap(Width); 1637 | pText->Advance(); 1638 | pWindow->AddTexture(pText); 1639 | } 1640 | } 1641 | 1642 | void NSBInterpreter::WaitText() 1643 | { 1644 | string Handle = PopString(); 1645 | int32_t Time = PopInt(); 1646 | 1647 | if (Text* pText = Get(Handle)) 1648 | if (!SkipHack) 1649 | pContext->WaitText(pText, Time); 1650 | } 1651 | 1652 | void NSBInterpreter::LockVideo() 1653 | { 1654 | /*bool Lock = */PopBool(); 1655 | } 1656 | 1657 | void NSBInterpreter::Save() 1658 | { 1659 | Npa::Buffer SaveData; 1660 | SaveData.Write(VariableHolder.Cache.size()); 1661 | vector > Arrays; 1662 | for (auto& var : VariableHolder.Cache) 1663 | { 1664 | if (var.first.front() == '#') 1665 | continue; 1666 | 1667 | SaveData.WriteStr32(NpaFile::FromUtf8(var.first)); 1668 | SaveData.WriteStr32(NpaFile::FromUtf8(var.first)); 1669 | SaveData.Write(var.second->GetTag()); 1670 | SaveData.Write(var.second->IsInt() ? var.second->ToInt() : 0); 1671 | SaveData.Write(var.second->IsFloat() ? var.second->ToFloat() : 0); 1672 | SaveData.WriteStr32(NpaFile::FromUtf8(var.second->IsString() ? var.second->ToString() : "")); 1673 | SaveData.Write(0); // unk - maybe bool? 4? 1674 | SaveData.WriteStr32(NpaFile::FromUtf8("")); // TODO: arrayref? 1675 | if (!var.second->Assoc.empty()) 1676 | Arrays.push_back(var); 1677 | } 1678 | SaveData.Write(Arrays.size()); 1679 | for (auto& arr : Arrays) 1680 | { 1681 | SaveData.WriteStr32(NpaFile::FromUtf8(arr.first)); 1682 | SaveData.Write(arr.second->Assoc.size()); 1683 | for (auto& i : arr.second->Assoc) 1684 | SaveData.WriteStr32(NpaFile::ToUtf8(i.first)); 1685 | } 1686 | fs::WriteFile(PopSave(), NpaFile::Encrypt(SaveData.GetData(), SaveData.GetSize()), SaveData.GetSize()); 1687 | } 1688 | 1689 | void NSBInterpreter::DeleteSaveFile() 1690 | { 1691 | string Filename = PopSave(); 1692 | fs::DeleteFile(Filename); 1693 | fs::DeleteDirectory(Filename.substr(0, Filename.size() - 4)); 1694 | } 1695 | 1696 | void NSBInterpreter::Conquest() 1697 | { 1698 | /*string unk = */PopString(); 1699 | /*string unk = */PopString(); 1700 | /*string unk = */PopBool(); 1701 | 1702 | // [HACK] 1703 | PushInt(0); 1704 | } 1705 | 1706 | void NSBInterpreter::ClearScore() 1707 | { 1708 | /*string unk = */PopString(); 1709 | } 1710 | 1711 | void NSBInterpreter::ClearBacklog() 1712 | { 1713 | } 1714 | 1715 | void NSBInterpreter::SetFont() 1716 | { 1717 | Text::dFont = PopString(); 1718 | Text::dSize = PopInt(); 1719 | Text::dInColor = PopColor(); 1720 | Text::dOutColor = PopColor(); 1721 | Text::dWeight = PopInt(); 1722 | Text::dAlign = PopString(); 1723 | } 1724 | 1725 | void NSBInterpreter::SetShortcut() 1726 | { 1727 | string Key = PopString(); 1728 | string Script = PopString(); 1729 | Shortcuts.push_back({SDLK_a + Key[0] - 'A', Script}); 1730 | } 1731 | 1732 | void NSBInterpreter::CreateClipTexture() 1733 | { 1734 | string Handle = PopString(); 1735 | int32_t Priority = PopInt(); 1736 | NSBPosition X1 = PopPos(); 1737 | NSBPosition Y1 = PopPos(); 1738 | int32_t X2 = PopInt(); 1739 | int32_t Y2 = PopInt(); 1740 | int32_t Width = PopInt(); 1741 | int32_t Height = PopInt(); 1742 | string Source = PopString(); 1743 | 1744 | Texture* pTexture = new Texture; 1745 | if (Source.size() < 4 || Source[Source.size() - 4] != '.') 1746 | pTexture->CreateFromImageClip(Get(Source), X2, Y2, Width, Height); 1747 | else 1748 | pTexture->CreateFromFileClip(Source, X2, Y2, Width, Height); 1749 | 1750 | pTexture->Move(X1(pTexture->GetWidth()), Y1(pTexture->GetHeight())); 1751 | pTexture->SetPriority(Priority); 1752 | 1753 | pWindow->AddTexture(pTexture); 1754 | ObjectHolder.Write(Handle, pTexture); 1755 | } 1756 | 1757 | void NSBInterpreter::ExistSave() 1758 | { 1759 | PushInt(fs::Exists(PopSave())); 1760 | } 1761 | 1762 | void NSBInterpreter::WaitAction() 1763 | { 1764 | string Handle = PopString(); 1765 | int32_t Time = pContext->GetNumParams() == 2 ? PopInt() : -1; 1766 | 1767 | if (Object* pObject = GetObject(Handle)) 1768 | pContext->WaitAction(pObject, Time); 1769 | } 1770 | 1771 | void NSBInterpreter::Load() 1772 | { 1773 | uint32_t Size; 1774 | char* pData = fs::ReadFile(PopSave(), Size); 1775 | Npa::Buffer SaveData(NpaFile::Decrypt(pData, Size), Size); 1776 | 1777 | uint32_t NumVars = SaveData.Read(); 1778 | for (uint32_t i = 0; i < NumVars; ++i) 1779 | { 1780 | string Name1 = NpaFile::ToUtf8(SaveData.ReadStr32()); 1781 | string Name2 = NpaFile::ToUtf8(SaveData.ReadStr32()); 1782 | /*uint32_t Type = */SaveData.Read(); 1783 | /*int32_t IntVal = */SaveData.Read(); 1784 | /*float FloatVal = */SaveData.Read(); 1785 | string StrVal = NpaFile::ToUtf8(SaveData.ReadStr32()); 1786 | /*bool unk = */SaveData.Read(); 1787 | string ArrayRef = NpaFile::ToUtf8(SaveData.ReadStr32()); 1788 | } 1789 | 1790 | uint32_t NumArrs = SaveData.Read(); 1791 | for (uint32_t i = 0; i < NumArrs; ++i) 1792 | { 1793 | string Name1 = NpaFile::ToUtf8(SaveData.ReadStr32()); 1794 | uint32_t NumElems = SaveData.Read(); 1795 | for (uint32_t j = 0; j < NumElems; ++j) 1796 | string Key = NpaFile::ToUtf8(SaveData.ReadStr32()); 1797 | } 1798 | } 1799 | 1800 | void NSBInterpreter::SetBacklog() 1801 | { 1802 | /*string Text = */PopString(); 1803 | /*string Voice = */PopString(); 1804 | 1805 | // [WORKAROUND] In JAST the third parameter may be an integer 1806 | Variable::Destroy(PopVar()); 1807 | ///*string Name = */PopString(); 1808 | } 1809 | 1810 | void NSBInterpreter::CreateText() 1811 | { 1812 | string Handle = PopString(); 1813 | int32_t Priority = PopInt(); 1814 | NSBPosition X = PopPos(); 1815 | NSBPosition Y = PopPos(); 1816 | NSBPosition Width = PopPos(); 1817 | /*NSBPosition Height = */PopPos(); 1818 | string String = PopString(); 1819 | 1820 | Text* pText = new Text; 1821 | pText->SetWrap(Width(0)); 1822 | pText->CreateFromString(String); 1823 | pText->SetPriority(Priority); 1824 | pText->SetPosition(X(pText->GetWidth()), Y(pText->GetHeight())); 1825 | 1826 | pWindow->AddTexture(pText); 1827 | ObjectHolder.Write(Handle, pText); 1828 | } 1829 | 1830 | void NSBInterpreter::AtExpression() 1831 | { 1832 | Variable* pVar = PopVar(); 1833 | pVar->Relative = true; 1834 | PushVar(pVar); 1835 | } 1836 | 1837 | void NSBInterpreter::Random() 1838 | { 1839 | PushInt(random() % PopInt()); 1840 | } 1841 | 1842 | void NSBInterpreter::CreateEffect() 1843 | { 1844 | string Handle = PopString(); 1845 | /*int32_t Priority = */PopInt(); 1846 | NSBPosition X = PopPos(); 1847 | NSBPosition Y = PopPos(); 1848 | /*int32_t Width = */PopInt(); 1849 | /*int32_t Height = */PopInt(); 1850 | /*int32_t Effect = */PopEffect(); 1851 | } 1852 | 1853 | void NSBInterpreter::SetTone() 1854 | { 1855 | if (Texture* pTexture = PopTexture()) 1856 | pTexture->SetTone(PopTone()); 1857 | } 1858 | 1859 | void NSBInterpreter::DateTime() 1860 | { 1861 | time_t t = time(nullptr); 1862 | tm* tms = localtime(&t); 1863 | PopVar()->Set(tms->tm_year + 1900); 1864 | PopVar()->Set(tms->tm_mon + 1); 1865 | PopVar()->Set(tms->tm_mday); 1866 | PopVar()->Set(tms->tm_hour); 1867 | PopVar()->Set(tms->tm_min); 1868 | PopVar()->Set(tms->tm_sec); 1869 | } 1870 | 1871 | void NSBInterpreter::Shake() 1872 | { 1873 | string Handle = PopString(); 1874 | int32_t Time = PopInt(); 1875 | int32_t XWidth = PopInt(); 1876 | int32_t YWidth = PopInt(); 1877 | /*int32_t unk1 = */PopInt(); 1878 | /*int32_t unk2 = */PopInt(); 1879 | /*int32_t unk3 = */PopInt(); 1880 | /*int32_t Tempo = */PopTempo(); 1881 | bool Wait = PopBool(); 1882 | 1883 | ObjectHolder.Execute(Handle, [Time, XWidth, YWidth] (Object** ppObject) 1884 | { 1885 | if (Texture* pTexture = dynamic_cast(*ppObject)) 1886 | pTexture->Shake(XWidth, YWidth, Time); 1887 | }); 1888 | 1889 | if (Wait) 1890 | pContext->Wait(Time); 1891 | } 1892 | 1893 | void NSBInterpreter::MoviePlay() 1894 | { 1895 | string File = PopString(); 1896 | /*bool unk = */PopBool(); 1897 | } 1898 | 1899 | void NSBInterpreter::SetStream() 1900 | { 1901 | string Handle = PopString(); 1902 | /*int32_t unk = */PopInt(); 1903 | } 1904 | 1905 | void NSBInterpreter::WaitPlay() 1906 | { 1907 | Playable* pPlayable = PopPlayable(); 1908 | /*string unk = */PopString(); 1909 | 1910 | pContext->Wait(pPlayable->RemainTime()); 1911 | } 1912 | 1913 | void NSBInterpreter::WaitFade() 1914 | { 1915 | Texture* pTexture = PopTexture(); 1916 | /*string unk = */PopString(); 1917 | 1918 | pContext->Wait(pTexture->RemainFade()); 1919 | } 1920 | 1921 | void NSBInterpreter::SoundAmplitude() 1922 | { 1923 | string Handle = PopString(); 1924 | /*string unk = */PopString(); 1925 | 1926 | // [HACK] 1927 | PushInt(0); 1928 | } 1929 | 1930 | void NSBInterpreter::Rotate() 1931 | { 1932 | Texture* pTexture = PopTexture(); 1933 | int32_t Time = PopInt(); 1934 | /*NSBPosition X = */PopRelative(); 1935 | /*NSBPosition Y = */PopRelative(); 1936 | NSBPosition Z = PopRelative(); 1937 | int32_t Tempo = PopTempo(); 1938 | bool Wait = PopBool(); 1939 | 1940 | pTexture->Rotate(Z(0, pTexture->GetAngle()), Time, Tempo); 1941 | if (Wait) 1942 | pContext->Wait(Time); 1943 | } 1944 | 1945 | void NSBInterpreter::Message() 1946 | { 1947 | static const map buttonret = 1948 | { 1949 | {"CANCEL", 0}, 1950 | {"OK", 1}, 1951 | {"YES", 2}, 1952 | {"NO", 3}, 1953 | {"ABORT", 4}, 1954 | {"RETRY", 5}, 1955 | {"IGNORE", 6} 1956 | }; 1957 | 1958 | static const string buttonstr[] = 1959 | { 1960 | "Cancel", "OK", "Yes", "No", "Abort", "Retry", "Ignore" 1961 | }; 1962 | 1963 | static const map > type 1964 | { 1965 | {"OKCANCEL", {"OK", "CANCEL"}}, 1966 | {"YESNO", {"YES", "NO"}}, 1967 | {"YESNOCANCEL", {"YES", "NO", "CANCEL"}}, 1968 | {"RETRYCANCEL", {"RETRY", "CANCEL"}}, 1969 | {"ABORTRETRYIGNORE", {"ABORT", "RETRY", "IGNORE"}} 1970 | }; 1971 | 1972 | static const map icon = 1973 | { 1974 | {"STOP", SDL_MESSAGEBOX_ERROR}, 1975 | {"INFORMATION", SDL_MESSAGEBOX_INFORMATION}, 1976 | {"EXCLAMATION", SDL_MESSAGEBOX_WARNING}, 1977 | {"QUESTION", SDL_MESSAGEBOX_INFORMATION} 1978 | }; 1979 | 1980 | string Title = PopString(); 1981 | string Text = PopString(); 1982 | string Type = PopString(); 1983 | string Icon = PopString(); 1984 | 1985 | vector Buttons; 1986 | for (const string& btnstr : type.at(Type)) 1987 | { 1988 | int ButtonRet = buttonret.at(btnstr); 1989 | Buttons.push_back({0, ButtonRet, buttonstr[ButtonRet].c_str()}); 1990 | } 1991 | 1992 | SDL_MessageBoxData Data = 1993 | { 1994 | icon.at(Icon), 1995 | NULL, 1996 | Title.c_str(), 1997 | Text.c_str(), 1998 | (int)Buttons.size(), 1999 | &Buttons[0], 2000 | NULL 2001 | }; 2002 | int RetVal; 2003 | SDL_ShowMessageBox(&Data, &RetVal); 2004 | PushInt(RetVal); 2005 | } 2006 | 2007 | void NSBInterpreter::Integer() 2008 | { 2009 | PushVar(PopVar()); 2010 | } 2011 | 2012 | void NSBInterpreter::CreateScrollbar() 2013 | { 2014 | string Handle = PopString(); 2015 | int32_t Priority = PopInt(); 2016 | int32_t X1 = PopInt(); 2017 | int32_t Y1 = PopInt(); 2018 | int32_t X2 = PopInt(); 2019 | int32_t Y2 = PopInt(); 2020 | /*int32_t unk1 = */PopInt(); 2021 | int32_t Min = PopInt(); 2022 | int32_t Max = PopInt(); 2023 | /*int32_t unk2 = */PopInt(); 2024 | /*int32_t unk3 = */PopInt(); 2025 | string Type = PopString(); 2026 | string Filename = PopString(); 2027 | string Callback = PopString(); 2028 | 2029 | Texture* pTexture = new Texture; 2030 | Scrollbar* pScrollbar = new Scrollbar(pTexture, X1, Y1, X2, Y2, Min, Max, Type, Callback); 2031 | pTexture->CreateFromFile(Filename); 2032 | pTexture->Move(X1, Y1); 2033 | pTexture->SetPriority(Priority); 2034 | pWindow->AddTexture(pTexture); 2035 | ObjectHolder.Write(Handle, pScrollbar); 2036 | } 2037 | 2038 | void NSBInterpreter::SetScrollbarValue() 2039 | { 2040 | Scrollbar* pScrollbar = PopScrollbar(); 2041 | int32_t Value = PopInt(); 2042 | pScrollbar->SetValue(Value); 2043 | } 2044 | 2045 | void NSBInterpreter::SetScrollbarWheelArea() 2046 | { 2047 | Scrollbar* pScrollbar = PopScrollbar(); 2048 | int32_t X = PopInt(); 2049 | int32_t Y = PopInt(); 2050 | int32_t Width = PopInt(); 2051 | int32_t Height = PopInt(); 2052 | pScrollbar->SetWheelArea(X, Y, Width, Height); 2053 | } 2054 | 2055 | void NSBInterpreter::ScrollbarValue() 2056 | { 2057 | Scrollbar* pScrollbar = PopScrollbar(); 2058 | PushInt(pScrollbar->GetValue()); 2059 | } 2060 | 2061 | void NSBInterpreter::CreateStencil() 2062 | { 2063 | string Handle = PopString(); 2064 | /*int32_t unk = */PopInt(); 2065 | NSBPosition X = PopPos(); 2066 | NSBPosition Y = PopPos(); 2067 | /*int32_t unk = */PopInt(); 2068 | string Filename = PopString(); 2069 | /*bool unk = */PopBool(); // Maybe Inheritance? 2070 | 2071 | // Hack 2072 | ObjectHolder.Write(Handle, new Name); 2073 | } 2074 | 2075 | void NSBInterpreter::CreateMask() 2076 | { 2077 | string Handle = PopString(); 2078 | /*int32_t Priority = */PopInt(); 2079 | NSBPosition X = PopPos(); 2080 | NSBPosition Y = PopPos(); 2081 | string Filename = PopString(); 2082 | /*bool Inheritance = */PopBool(); 2083 | 2084 | // Hack 2085 | ObjectHolder.Write(Handle, new Name); 2086 | } 2087 | -------------------------------------------------------------------------------- /src/Playable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2013-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "Movie.hpp" 19 | #include "nsbconstants.hpp" 20 | #include 21 | #include 22 | 23 | GstBusSyncReply SyncHandler(GstBus* bus, GstMessage* msg, gpointer Handle) 24 | { 25 | if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_EOS) 26 | ((Playable*)Handle)->OnEOS(); 27 | else 28 | return GST_BUS_PASS; 29 | 30 | gst_message_unref(msg); 31 | return GST_BUS_DROP; 32 | } 33 | 34 | void LinkPad(GstElement* DecodeBin, GstPad* SourcePad, gpointer Data) 35 | { 36 | GstCaps* Caps = gst_pad_query_caps(SourcePad, nullptr); 37 | GstStructure* Struct = gst_caps_get_structure(Caps, 0); 38 | 39 | GstPad* SinkPad; 40 | if (g_strrstr(gst_structure_get_name(Struct), "video")) 41 | SinkPad = gst_element_get_static_pad(((Movie*)Data)->VideoBin, "sink"); 42 | else if (g_strrstr(gst_structure_get_name(Struct), "audio")) 43 | SinkPad = gst_element_get_static_pad(((Playable*)Data)->AudioBin, "sink"); 44 | else 45 | SinkPad = nullptr; 46 | 47 | if (SinkPad && !gst_pad_is_linked(SinkPad)) 48 | gst_pad_link(SourcePad, SinkPad); 49 | 50 | if (SinkPad) 51 | g_object_unref(SinkPad); 52 | gst_caps_unref(Caps); 53 | } 54 | 55 | static bool SeekData(GstAppSrc* Appsrc, guint64 Offset, AppSrc* pAppsrc) 56 | { 57 | pAppsrc->Offset = Offset; 58 | return true; 59 | } 60 | 61 | static void FeedData(GstElement* Pipeline, guint size, AppSrc* pAppsrc) 62 | { 63 | gsize Size = 4096; 64 | if (pAppsrc->Offset + Size > pAppsrc->File.GetSize()) 65 | { 66 | if (pAppsrc->Offset >= pAppsrc->File.GetSize()) 67 | { 68 | gst_app_src_end_of_stream(pAppsrc->Appsrc); 69 | return; 70 | } 71 | Size = pAppsrc->File.GetSize() - pAppsrc->Offset; 72 | } 73 | char* pData = pAppsrc->File.ReadData(pAppsrc->Offset, Size); 74 | GstBuffer* Buffer = gst_buffer_new_wrapped(pData, Size); 75 | gst_app_src_push_buffer(pAppsrc->Appsrc, Buffer); 76 | pAppsrc->Offset += Size; 77 | } 78 | 79 | AppSrc::AppSrc(Resource& Res) : Offset(0), File(Res) 80 | { 81 | Appsrc = (GstAppSrc*)gst_element_factory_make("appsrc", nullptr); 82 | if (!Appsrc) 83 | cerr << "Failed to create appsrc" << endl; 84 | 85 | gst_app_src_set_stream_type(Appsrc, GST_APP_STREAM_TYPE_RANDOM_ACCESS); 86 | gst_app_src_set_size(Appsrc, Res.GetSize()); 87 | g_signal_connect(Appsrc, "need-data", G_CALLBACK(FeedData), this); 88 | g_signal_connect(Appsrc, "seek-data", G_CALLBACK(SeekData), this); 89 | } 90 | 91 | Playable::Playable(const string& FileName) : 92 | Appsrc(nullptr), 93 | Playing(false), 94 | Loop(false), 95 | AudioBin(nullptr), 96 | Begin(0), 97 | End(0) 98 | { 99 | GstElement* Filesrc = gst_element_factory_make("filesrc", nullptr); 100 | if (!Filesrc) 101 | cerr << "Failed to create filesrc" << endl; 102 | 103 | g_object_set(G_OBJECT(Filesrc), "location", FileName.c_str(), nullptr); 104 | InitPipeline(Filesrc); 105 | } 106 | 107 | Playable::Playable(Resource Res) : 108 | Appsrc(new AppSrc(Res)), 109 | Loop(false), 110 | Begin(0) 111 | { 112 | InitPipeline((GstElement*)Appsrc->Appsrc); 113 | InitAudio(); 114 | } 115 | 116 | Playable::~Playable() 117 | { 118 | Stop(); 119 | gst_object_unref(GST_OBJECT(Pipeline)); 120 | } 121 | 122 | void Playable::InitPipeline(GstElement* Source) 123 | { 124 | Pipeline = gst_pipeline_new("pipeline"); 125 | GstElement* Decodebin = gst_element_factory_make("decodebin", nullptr); 126 | if (!Decodebin) 127 | cerr << "Failed to create decodebin" << endl; 128 | 129 | g_signal_connect(Decodebin, "pad-added", G_CALLBACK(LinkPad), this); 130 | gst_bin_add_many(GST_BIN(Pipeline), Source, Decodebin, nullptr); 131 | 132 | if (!gst_element_link(Source, Decodebin)) 133 | cerr << "Failed to link file/appsrc | decodebin" << endl; 134 | 135 | // Set sync handler 136 | GstBus* Bus = gst_pipeline_get_bus(GST_PIPELINE(Pipeline)); 137 | gst_bus_set_sync_handler(Bus, (GstBusSyncHandler)SyncHandler, this, nullptr); 138 | gst_object_unref(Bus); 139 | } 140 | 141 | void Playable::InitAudio() 142 | { 143 | AudioBin = gst_bin_new("audiobin"); 144 | GstElement* AudioConv = gst_element_factory_make("audioconvert", nullptr); 145 | if (!AudioConv) 146 | cerr << "Failed to create audioconvert" << endl; 147 | 148 | GstElement* AudioSink = gst_element_factory_make("autoaudiosink", nullptr); 149 | if (!AudioSink) 150 | cerr << "Failed to create autoaudiosink" << endl; 151 | 152 | VolumeFilter = gst_element_factory_make("volume", nullptr); 153 | if (!VolumeFilter) 154 | cerr << "Failed to create volume" << endl; 155 | 156 | gst_bin_add_many(GST_BIN(AudioBin), AudioConv, VolumeFilter, AudioSink, nullptr); 157 | if (!gst_element_link_many(AudioConv, VolumeFilter, AudioSink, nullptr)) 158 | cerr << "Failed to link audioconvert | volume | autoaudiosink" << endl; 159 | 160 | GstPad* AudioPad = gst_element_get_static_pad(AudioConv, "sink"); 161 | if (!AudioPad) 162 | cerr << "Failed to get pad" << endl; 163 | 164 | if (!gst_element_add_pad(AudioBin, gst_ghost_pad_new("sink", AudioPad))) 165 | cerr << "Failed to add ghost sink pad" << endl; 166 | 167 | gst_object_unref(AudioPad); 168 | gst_bin_add(GST_BIN(Pipeline), AudioBin); 169 | } 170 | 171 | // TODO: Should this->End rather than Length be taken into consideration? 172 | // TODO: Maybe DurationTime() - PassageTime() ? 173 | int32_t Playable::RemainTime() 174 | { 175 | gint64 Length, Position; 176 | gst_element_query_duration(Pipeline, GST_FORMAT_TIME, &Length); 177 | gst_element_query_position(Pipeline, GST_FORMAT_TIME, &Position); 178 | return (Length - Position) / GST_MSECOND; 179 | } 180 | 181 | // TODO: Should this->Start be substracted from this? 182 | int32_t Playable::DurationTime() 183 | { 184 | gint64 Length; 185 | gst_element_query_duration(Pipeline, GST_FORMAT_TIME, &Length); 186 | return Length / GST_MSECOND; 187 | } 188 | 189 | int32_t Playable::PassageTime() 190 | { 191 | gint64 Position; 192 | gst_element_query_position(Pipeline, GST_FORMAT_TIME, &Position); 193 | return Position / GST_MSECOND; 194 | } 195 | 196 | void Playable::SetLoop(bool Loop) 197 | { 198 | this->Loop = Loop; 199 | } 200 | 201 | void Playable::Stop() 202 | { 203 | gst_element_set_state(Pipeline, GST_STATE_NULL); 204 | } 205 | 206 | void Playable::Play() 207 | { 208 | GstStateChangeReturn ret = gst_element_set_state(Pipeline, GST_STATE_PLAYING); 209 | if (ret == GST_STATE_CHANGE_ASYNC) 210 | ret = gst_element_get_state(Pipeline, nullptr, nullptr, GST_CLOCK_TIME_NONE); 211 | if (ret == GST_STATE_CHANGE_FAILURE) 212 | cerr << "Failed to set pipline state to PLAYING" << endl; 213 | gst_element_seek_simple(Pipeline, GST_FORMAT_TIME, GST_SEEK_FLAG_FLUSH, Begin); 214 | ret = gst_element_get_state(Pipeline, nullptr, nullptr, GST_CLOCK_TIME_NONE); 215 | if (ret == GST_STATE_CHANGE_FAILURE) 216 | cerr << "Failed to seek" << endl; 217 | } 218 | 219 | void Playable::SetVolume(int32_t Time, int32_t Volume, int32_t Tempo) 220 | { 221 | g_object_set(G_OBJECT(VolumeFilter), "volume", Volume / 1000.0, NULL); 222 | } 223 | 224 | void Playable::SetFrequency(int32_t Time, int32_t Frequency, int32_t Tempo) 225 | { 226 | } 227 | 228 | void Playable::SetPan(int32_t Time, int32_t Pan, int32_t Tempo) 229 | { 230 | } 231 | 232 | void Playable::SetLoopPoint(int32_t Begin, int32_t End) 233 | { 234 | this->Begin = Begin * GST_MSECOND; 235 | this->End = End * GST_MSECOND; 236 | } 237 | 238 | void Playable::OnEOS() 239 | { 240 | if (Loop) 241 | thread([this](){Play();}).detach(); 242 | } 243 | 244 | void Playable::Request(int32_t State) 245 | { 246 | Object::Request(State); 247 | switch (State) 248 | { 249 | case Nsb::RESUME: 250 | Playing = true; 251 | gst_element_set_state(Pipeline, GST_STATE_PLAYING); 252 | break; 253 | case Nsb::PLAY: 254 | Playing = true; 255 | Play(); 256 | break; 257 | case Nsb::PAUSE: 258 | Playing = false; 259 | gst_element_set_state(Pipeline, GST_STATE_PAUSED); 260 | break; 261 | } 262 | } 263 | 264 | // [HACK] 265 | bool Playable::Action() 266 | { 267 | return RemainTime() <= 0; 268 | } 269 | -------------------------------------------------------------------------------- /src/ResourceMgr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2013-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "ResourceMgr.hpp" 19 | #include "scriptfile.hpp" 20 | #include 21 | 22 | char* Resource::ReadData(uint32_t Offset, uint32_t Size) 23 | { 24 | return pArchive->ReadData(File, Offset, Size, g_malloc); 25 | } 26 | 27 | ResourceMgr* sResourceMgr; 28 | 29 | ResourceMgr::ResourceMgr() 30 | { 31 | } 32 | 33 | ResourceMgr::~ResourceMgr() 34 | { 35 | for_each(Archives.begin(), Archives.end(), default_delete()); 36 | } 37 | 38 | Resource ResourceMgr::GetResource(string Path) 39 | { 40 | transform(Path.begin(), Path.end(), Path.begin(), ::tolower); 41 | for (uint32_t i = 0; i < Archives.size(); ++i) 42 | { 43 | auto File = Archives[i]->FindFile(Path); 44 | if (File != Archives[i]->End()) 45 | return Resource(Archives[i], File); 46 | } 47 | return Resource(nullptr, Archives[0]->End()); 48 | } 49 | 50 | char* ResourceMgr::Read(string Path, uint32_t& Size) 51 | { 52 | transform(Path.begin(), Path.end(), Path.begin(), ::tolower); 53 | for (uint32_t i = 0; i < Archives.size(); ++i) 54 | if (char* pData = Archives[i]->ReadFile(Path, Size)) 55 | return pData; 56 | 57 | cout << "Failed to read " << Path << endl; 58 | Size = 0; 59 | return nullptr; 60 | } 61 | 62 | ScriptFile* ResourceMgr::GetScriptFile(const string& Path) 63 | { 64 | if (ScriptFile* pCache = CacheHolder.Read(Path)) 65 | return pCache; 66 | 67 | ScriptFile* pScript = ReadScriptFile(Path); 68 | if (!pScript) 69 | return nullptr; 70 | 71 | for (const string& i : pScript->GetIncludes()) 72 | GetScriptFile(i); 73 | 74 | CacheHolder.Write(Path, pScript); 75 | return pScript; 76 | } 77 | 78 | ScriptFile* ResourceMgr::ResolveSymbol(const string& Symbol, uint32_t& CodeLine) 79 | { 80 | for (auto& i : CacheHolder.Cache) 81 | { 82 | CodeLine = i.second->GetSymbol(Symbol); 83 | if (CodeLine != NSB_INVALIDE_LINE) 84 | return i.second; 85 | } 86 | return nullptr; 87 | } 88 | -------------------------------------------------------------------------------- /src/Scrollbar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "Scrollbar.hpp" 19 | #include "Window.hpp" 20 | #include "Texture.hpp" 21 | 22 | Scrollbar::Scrollbar(Texture* pTexture, int32_t X1, int32_t Y1, int32_t X2, int32_t Y2, int32_t Min, int32_t Max, string Type, string Callback) : 23 | pTexture(pTexture), X1(X1), Y1(Y1), X2(X2), Y2(Y2), Min(Min), Max(Max), Type(Type), Callback(Callback) 24 | { 25 | } 26 | 27 | Scrollbar::~Scrollbar() 28 | { 29 | pWindow->RemoveTexture(pTexture); 30 | delete pTexture; 31 | } 32 | 33 | void Scrollbar::SetWheelArea(int32_t X, int32_t Y, int32_t Width, int32_t Height) 34 | { 35 | WX = X; 36 | WY = Y; 37 | WWidth = Width; 38 | WHeight = Height; 39 | } 40 | 41 | void Scrollbar::SetValue(int32_t NewValue) 42 | { 43 | Value = NewValue; 44 | } 45 | 46 | int32_t Scrollbar::GetValue() 47 | { 48 | return Value; 49 | } 50 | -------------------------------------------------------------------------------- /src/Text.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "Text.hpp" 19 | #include "Playable.hpp" 20 | #define yyparse xmlparse 21 | #define yy_scan_bytes xml_scan_bytes 22 | #define yy_delete_buffer xml_delete_buffer 23 | #include "flex.hpp" 24 | #include 25 | 26 | // For use in bison 27 | TextParser::Text* pText; 28 | 29 | string Text::dFont; 30 | int32_t Text::dSize; 31 | uint32_t Text::dInColor; 32 | uint32_t Text::dOutColor; 33 | int32_t Text::dWeight; 34 | string Text::dAlign; 35 | 36 | class VoiceMgr 37 | { 38 | public: 39 | VoiceMgr() : pVoice(nullptr) 40 | { 41 | } 42 | 43 | ~VoiceMgr() 44 | { 45 | delete pVoice; 46 | } 47 | 48 | void SetVoice(const string& Filename) 49 | { 50 | delete pVoice; 51 | pVoice = new Playable(sResourceMgr->GetResource(Filename + ".ogg")); 52 | pVoice->Play(); 53 | } 54 | 55 | private: 56 | Playable* pVoice; 57 | } sVoiceMgr; 58 | 59 | Text::Text() : Index(0), LayoutWidth(-1), Size(dSize), Color(dInColor) 60 | { 61 | } 62 | 63 | Text::~Text() 64 | { 65 | } 66 | 67 | void Text::CreateFromXML(const string& XML) 68 | { 69 | ::pText = this; 70 | YY_BUFFER_STATE buffer = yy_scan_bytes(XML.c_str(), XML.size()); 71 | yyparse(); 72 | yy_delete_buffer(buffer); 73 | } 74 | 75 | void Text::CreateFromString(const string& String) 76 | { 77 | SetString(String); 78 | } 79 | 80 | void Text::SetCharacterSize(uint32_t Size) 81 | { 82 | this->Size = Size; 83 | } 84 | 85 | void Text::SetColor(uint32_t Color) 86 | { 87 | this->Color = Color; 88 | } 89 | 90 | void Text::SetWrap(int32_t Width) 91 | { 92 | LayoutWidth = Width; 93 | } 94 | 95 | bool Text::Advance() 96 | { 97 | if (Index == Lines.size()) 98 | return false; 99 | 100 | TextParser::Line& CurrLine = Lines[Index]; 101 | 102 | // [HACK] 103 | string String; 104 | for (size_t i = 0; i < CurrLine.StringSegs.size(); ++i) 105 | String += CurrLine.StringSegs[CurrLine.StringSegs.size() - i - 1].Segment; 106 | SetString(String); 107 | 108 | if (!CurrLine.VoiceAttrs.empty()) 109 | sVoiceMgr.SetVoice(CurrLine.VoiceAttrs[TextParser::ATTR_SRC]); 110 | Index++; 111 | return true; 112 | } 113 | 114 | void Text::SetString(const string& String) 115 | { 116 | cairo_surface_t* TempSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); 117 | cairo_t* LayoutContext = cairo_create(TempSurface); 118 | cairo_surface_destroy(TempSurface); 119 | 120 | PangoLayout* Layout = pango_cairo_create_layout(LayoutContext); 121 | pango_layout_set_width(Layout, LayoutWidth * PANGO_SCALE); 122 | pango_layout_set_wrap(Layout, PANGO_WRAP_WORD_CHAR); 123 | pango_layout_set_text(Layout, String.c_str(), -1); 124 | 125 | PangoFontDescription* Desc = pango_font_description_from_string("Sans 18"); 126 | pango_font_description_set_absolute_size(Desc, Size * PANGO_SCALE); 127 | pango_font_description_set_weight(Desc, PANGO_WEIGHT_MEDIUM); 128 | pango_layout_set_font_description(Layout, Desc); 129 | pango_font_description_free(Desc); 130 | 131 | pango_layout_get_pixel_size(Layout, &Width, &Height); 132 | uint8_t* pData = (uint8_t*)calloc(4 * Width * Height, sizeof(uint8_t)); 133 | cairo_surface_t* Surface = cairo_image_surface_create_for_data(pData, CAIRO_FORMAT_ARGB32, Width, Height, 4 * Width); 134 | cairo_t* RenderContext = cairo_create(Surface); 135 | 136 | cairo_set_source_rgba(RenderContext, Color & 0xFF, (Color >> 8) & 0xFF, (Color >> 16) & 0xFF, Color >> 24); 137 | pango_cairo_show_layout(RenderContext, Layout); 138 | Create(pData, GL_RGBA, Width, Height); 139 | 140 | free(pData); 141 | g_object_unref(Layout); 142 | cairo_destroy(LayoutContext); 143 | cairo_destroy(RenderContext); 144 | cairo_surface_destroy(Surface); 145 | } 146 | 147 | void Text::Request(int32_t State) 148 | { 149 | } 150 | -------------------------------------------------------------------------------- /src/Texture.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "Effect.hpp" 19 | #include "Window.hpp" 20 | #include "Image.hpp" 21 | 22 | Texture::Texture() : 23 | pMove(nullptr), 24 | pZoom(nullptr), 25 | pFade(nullptr), 26 | pMask(nullptr), 27 | pBlur(nullptr), 28 | pRotate(nullptr), 29 | pTone(nullptr), 30 | X(0), Y(0), OX(0), OY(0), 31 | Angle(0), 32 | XScale(1000), YScale(1000), 33 | XShake(0), YShake(0), ShakeTime(0), ShakeTick(false) 34 | { 35 | } 36 | 37 | Texture::~Texture() 38 | { 39 | pWindow->RemoveTexture(this); 40 | delete pMove; 41 | delete pZoom; 42 | delete pFade; 43 | delete pMask; 44 | delete pBlur; 45 | } 46 | 47 | void Texture::Request(int32_t State) 48 | { 49 | Object::Request(State); 50 | switch (State) 51 | { 52 | case Nsb::SMOOTHING: 53 | SetSmoothing(true); 54 | break; 55 | case Nsb::ERASE: 56 | pWindow->RemoveTexture(this); 57 | break; 58 | case Nsb::ENTER: 59 | pWindow->AddTexture(this); 60 | break; 61 | } 62 | } 63 | 64 | void Texture::CreateFromGLTexture(GLTexture* pTexture) 65 | { 66 | GLTextureID = pTexture->GLTextureID; 67 | Width = pTexture->Width; 68 | Height = pTexture->Height; 69 | } 70 | 71 | void Texture::SetPosition(int X, int Y) 72 | { 73 | this->X = X; 74 | this->Y = Y; 75 | } 76 | 77 | void Texture::SetAngle(int Angle) 78 | { 79 | this->Angle = Angle; 80 | } 81 | 82 | void Texture::SetScale(int XScale, int YScale) 83 | { 84 | this->XScale = XScale; 85 | this->YScale = YScale; 86 | } 87 | 88 | void Texture::SetVertex(int X, int Y) 89 | { 90 | OX = X; 91 | OY = Y; 92 | } 93 | 94 | void Texture::SetPriority(int Priority) 95 | { 96 | this->Priority = Priority; 97 | } 98 | 99 | void Texture::Move(int X, int Y, int32_t Time, int32_t Tempo) 100 | { 101 | if (!pMove) 102 | pMove = new MoveEffect(X, Y, Time, Tempo); 103 | else 104 | pMove->Reset(X, Y, Time, Tempo); 105 | } 106 | 107 | void Texture::Zoom(int32_t Time, int X, int Y, int32_t Tempo) 108 | { 109 | if (!pZoom) 110 | pZoom = new ZoomEffect(X, Y, Time, Tempo); 111 | else 112 | pZoom->Reset(X, Y, Time, Tempo); 113 | } 114 | 115 | void Texture::Fade(int32_t Time, int Opacity, int32_t Tempo) 116 | { 117 | if (!pFade) 118 | pFade = new FadeEffect(Opacity, Time, Tempo); 119 | else 120 | pFade->Reset(Opacity, 0, Time, Tempo); 121 | } 122 | 123 | void Texture::DrawTransition(int32_t Time, int32_t Start, int32_t End, int32_t Boundary, int32_t Tempo, const string& Filename) 124 | { 125 | if (!pMask) 126 | pMask = new MaskEffect(Filename, Start, End, Time, Boundary, Tempo); 127 | else 128 | pMask->Reset(Filename, Start, End, Time, Boundary, Tempo); 129 | } 130 | 131 | void Texture::SetShade(int32_t Shade) 132 | { 133 | /* TODO: These are wrong */ 134 | static const float Sigma[] = 135 | { 136 | 0.5, 1, 1.5, 2, 2.5, 3, 3.5 137 | }; 138 | delete pBlur; 139 | pBlur = new BlurEffect; 140 | if (!pBlur->Create(Width, Height, Sigma[Shade])) 141 | { 142 | delete pBlur; 143 | pBlur = nullptr; 144 | } 145 | } 146 | 147 | void Texture::SetTone(int32_t Tonei) 148 | { 149 | delete pTone; 150 | pTone = new Tone(Tonei); 151 | } 152 | 153 | void Texture::Rotate(int32_t Angle, int32_t Time, int32_t Tempo) 154 | { 155 | if (!pRotate) 156 | pRotate = new RotateEffect(Angle, Time, Tempo); 157 | else 158 | pRotate->Reset(Angle, 0, Time, Tempo); 159 | } 160 | 161 | void Texture::Shake(int32_t XWidth, int32_t YWidth, int32_t Time) 162 | { 163 | XShake = XWidth; 164 | YShake = YWidth; 165 | ShakeTime = Time; 166 | } 167 | 168 | void Texture::UpdateEffects(uint32_t Diff) 169 | { 170 | if (pMove) pMove->OnDraw(this, Diff); 171 | if (pRotate) pRotate->OnDraw(this, Diff); 172 | if (pZoom) pZoom->OnDraw(this, Diff); 173 | if (pFade) pFade->OnDraw(Diff); 174 | if (pMask) pMask->OnDraw(Diff); 175 | if (pTone) pTone->OnDraw(); 176 | } 177 | 178 | void Texture::Draw(uint32_t Diff) 179 | { 180 | UpdateEffects(Diff); 181 | ShakeTime = max(0, ShakeTime - (int32_t)Diff); 182 | ShakeTick = ShakeTime ? !ShakeTick : false; 183 | 184 | float sx = XScale / 1000.f; 185 | float sy = YScale / 1000.f; 186 | float ox = OX * (1.f - sx); 187 | float oy = OY * (1.f - sy); 188 | float s = sin(Angle * M_PI / 180.); 189 | float c = cos(Angle * M_PI / 180.); 190 | float XA[4] = {(float)X, X + Width * sx, X + Width * sx, (float)X}; 191 | float YA[4] = {(float)Y, (float)Y, Y + Height * sy, Y + Height * sy}; 192 | for (int i = 0; i < 4; ++i) 193 | { 194 | XA[i] -= X + OX * sx; 195 | YA[i] -= Y + OY * sy; 196 | float xn = XA[i] * c - YA[i] * s; 197 | float yn = XA[i] * s + YA[i] * c; 198 | XA[i] = xn + X + OX * sx + ox; 199 | YA[i] = yn + Y + OY * sy + oy; 200 | XA[i] += ShakeTick * XShake; 201 | YA[i] += ShakeTick * YShake; 202 | } 203 | 204 | if (pBlur) pBlur->OnDraw(this, XA, YA, Width * sx, Height * sy); 205 | else GLTexture::Draw(XA, YA); 206 | 207 | if (glUseProgramObjectARB) 208 | glUseProgramObjectARB(0); 209 | } 210 | 211 | int32_t Texture::GetMX() 212 | { 213 | return pMove ? pMove->EndX : 0; 214 | } 215 | 216 | int32_t Texture::GetMY() 217 | { 218 | return pMove ? pMove->EndY : 0; 219 | } 220 | 221 | int32_t Texture::RemainFade() 222 | { 223 | return max(0, pFade->Time - pFade->ElapsedTime); 224 | } 225 | -------------------------------------------------------------------------------- /src/Variable.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include "Variable.hpp" 19 | #include "nsbconstants.hpp" 20 | #include 21 | 22 | Variable::Variable() : Literal(true), Relative(false) 23 | { 24 | } 25 | 26 | Variable::~Variable() 27 | { 28 | } 29 | 30 | void Variable::Set(int32_t Int) 31 | { 32 | Val.Int = Int; 33 | Val.Str = ""; 34 | Tag = NSB_INT; 35 | } 36 | 37 | void Variable::Set(float Float) 38 | { 39 | Val.Float = Float; 40 | Val.Str = ""; 41 | Tag = NSB_FLOAT; 42 | } 43 | 44 | void Variable::Set(const string& Str) 45 | { 46 | Val.Str = Str; 47 | // hack 48 | if (Str[0] == '@') 49 | { 50 | Relative = true; 51 | try 52 | { 53 | stoi(Val.Str.c_str() + 1); 54 | } 55 | catch(...) 56 | { 57 | Relative = false; 58 | } 59 | } 60 | Tag = NSB_STRING; 61 | } 62 | 63 | void Variable::Initialize() 64 | { 65 | Tag = NSB_NULL; 66 | } 67 | 68 | void Variable::Initialize(Variable* pVar) 69 | { 70 | if (pVar->Tag == NSB_NULL) 71 | Initialize(); 72 | else if (pVar->IsString()) 73 | Set(pVar->ToString()); 74 | else 75 | Set(pVar->ToInt()); 76 | } 77 | 78 | Variable* Variable::MakeFloat(float Float) 79 | { 80 | Variable* pVar = new Variable; 81 | pVar->Set(Float); 82 | return pVar; 83 | } 84 | 85 | Variable* Variable::MakeInt(int32_t Int) 86 | { 87 | Variable* pVar = new Variable; 88 | pVar->Set(Int); 89 | return pVar; 90 | } 91 | 92 | Variable* Variable::MakeString(const string& Str) 93 | { 94 | Variable* pVar = new Variable; 95 | pVar->Set(Str); 96 | return pVar; 97 | } 98 | 99 | Variable* Variable::MakeNull(const string& Name) 100 | { 101 | Variable* pVar = new Variable; 102 | pVar->Literal = false; 103 | pVar->Name = Name; 104 | pVar->Initialize(); 105 | return pVar; 106 | } 107 | 108 | Variable* Variable::MakeCopy(Variable* pVar, const string& Name) 109 | { 110 | Variable* pNew = new Variable; 111 | pNew->Literal = false; 112 | pNew->Name = Name; 113 | pNew->Initialize(pVar); 114 | Variable::Destroy(pVar); 115 | return pNew; 116 | } 117 | 118 | int Variable::GetTag() 119 | { 120 | return Tag; 121 | } 122 | 123 | float Variable::ToFloat() 124 | { 125 | return Val.Float; 126 | } 127 | 128 | int32_t Variable::ToInt() 129 | { 130 | if (Tag == NSB_NULL) 131 | return 0; 132 | 133 | if (Tag == NSB_STRING) 134 | { 135 | int32_t Value = Nsb::ConstantToValue(ToString()); 136 | if (Value != -1) 137 | return Value; 138 | return Relative ? stoi(Val.Str.c_str() + 1) : 0; 139 | } 140 | 141 | return Val.Int; 142 | } 143 | 144 | string Variable::ToString() 145 | { 146 | if (Tag == NSB_NULL) 147 | return ""; 148 | 149 | if (Tag == NSB_INT) 150 | return Relative ? string("@") + to_string(Val.Int) : to_string(Val.Int); 151 | 152 | return Val.Str; 153 | } 154 | 155 | bool Variable::IsFloat() 156 | { 157 | return Tag == NSB_FLOAT; 158 | } 159 | 160 | bool Variable::IsInt() 161 | { 162 | return Tag == NSB_INT || Tag == NSB_NULL || Relative || Nsb::ConstantToValue(Val.Str) != -1; 163 | } 164 | 165 | bool Variable::IsString() 166 | { 167 | return Tag == NSB_STRING || Tag == NSB_NULL || Relative; 168 | } 169 | 170 | bool Variable::IsNull() 171 | { 172 | return Tag == NSB_NULL; 173 | } 174 | 175 | void Variable::Set(Variable* pVar) 176 | { 177 | Initialize(pVar); 178 | } 179 | 180 | Variable* Variable::IntUnaryOp(function Func) 181 | { 182 | Val.Int = Func(Val.Int); 183 | return this; 184 | } 185 | 186 | Variable* Variable::Add(Variable* pFirst, Variable* pSecond) 187 | { 188 | Variable* pThird = nullptr; 189 | if (pFirst->IsInt()) 190 | pThird = MakeInt(pFirst->ToInt() + pSecond->ToInt()); 191 | else if (pFirst->IsString()) 192 | pThird = MakeString(pFirst->ToString() + pSecond->ToString()); 193 | 194 | Destroy(pFirst); 195 | Destroy(pSecond); 196 | return pThird; 197 | } 198 | 199 | void Variable::Destroy(Variable* pVar) 200 | { 201 | if (pVar->Literal) 202 | delete pVar; 203 | } 204 | -------------------------------------------------------------------------------- /src/Window.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libnpengine: Nitroplus script interpreter 3 | * Copyright (C) 2014-2016,2018 Mislav Blažević 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU Lesser Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU Lesser Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser Public License 16 | * along with this program. If not, see . 17 | * */ 18 | #include 19 | #include 20 | #include "NSBInterpreter.hpp" 21 | #include "Window.hpp" 22 | #include "Texture.hpp" 23 | 24 | uint32_t SDL_NSB_MOVECURSOR; 25 | Window* Object::pWindow = nullptr; 26 | 27 | Window::Window(const char* WindowTitle, const int Width, const int Height) : WIDTH(Width), HEIGHT(Height), pInterpreter(nullptr), IsRunning(true), EventLoop(false) 28 | { 29 | Object::pWindow = this; 30 | SDL_Init(SDL_INIT_VIDEO); 31 | SDLWindow = SDL_CreateWindow(WindowTitle, 0, 0, WIDTH, HEIGHT, SDL_WINDOW_OPENGL); 32 | GLContext = SDL_GL_CreateContext(SDLWindow); 33 | SDL_NSB_MOVECURSOR = SDL_RegisterEvents(1); 34 | 35 | GLenum err = glewInit(); 36 | if (err != GLEW_OK) 37 | cout << glewGetErrorString(err) << endl; 38 | 39 | glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 40 | glViewport(0, 0, WIDTH, HEIGHT); 41 | glEnable(GL_BLEND); 42 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 43 | glEnable(GL_TEXTURE_2D); 44 | glMatrixMode(GL_PROJECTION); 45 | glLoadIdentity(); 46 | glOrtho(0, WIDTH, HEIGHT, 0, -1, 1); 47 | } 48 | 49 | Window::~Window() 50 | { 51 | SDL_GL_DeleteContext(GLContext); 52 | SDL_DestroyWindow(SDLWindow); 53 | SDL_Quit(); 54 | delete pInterpreter; 55 | } 56 | 57 | void Window::PushMoveCursorEvent(int X, int Y) 58 | { 59 | SDL_Event Event; 60 | SDL_zero(Event); 61 | Event.type = SDL_NSB_MOVECURSOR; 62 | Event.user.data1 = reinterpret_cast(X); 63 | Event.user.data2 = reinterpret_cast(Y); 64 | SDL_PushEvent(&Event); 65 | } 66 | 67 | void Window::Run() 68 | { 69 | LastDrawTime = SDL_GetTicks(); 70 | SDL_Event Event; 71 | while (IsRunning) 72 | { 73 | while (SDL_PollEvent(&Event)) 74 | HandleEvent(Event); 75 | 76 | Draw(); 77 | pInterpreter->Run(100); 78 | SDL_Delay(10); 79 | } 80 | } 81 | 82 | void Window::Exit() 83 | { 84 | IsRunning = false; 85 | } 86 | 87 | void Window::Select(bool Enable) 88 | { 89 | EventLoop = Enable; 90 | } 91 | 92 | void Window::HandleEvent(SDL_Event& Event) 93 | { 94 | if (Event.type == SDL_NSB_MOVECURSOR) 95 | MoveCursor((int64_t)Event.user.data1, (int64_t)Event.user.data2); 96 | else if (EventLoop) 97 | pInterpreter->PushEvent(Event); 98 | 99 | pInterpreter->HandleEvent(Event); 100 | } 101 | 102 | void Window::Draw() 103 | { 104 | uint32_t CurrTime = SDL_GetTicks(); 105 | uint32_t Diff = CurrTime - LastDrawTime; 106 | DrawTextures(Diff); 107 | pInterpreter->Update(Diff); 108 | SDL_GL_SwapWindow(SDLWindow); 109 | LastDrawTime = CurrTime; 110 | } 111 | 112 | void Window::DrawTextures(uint32_t Diff) 113 | { 114 | glClear(GL_COLOR_BUFFER_BIT); 115 | for (Texture* pTex : Textures) 116 | pTex->Draw(Diff); 117 | } 118 | 119 | void Window::AddTexture(Texture* pTexture) 120 | { 121 | auto Spot = Textures.begin(); 122 | while (Spot != Textures.end()) 123 | { 124 | if ((*Spot)->GetPriority() > pTexture->GetPriority()) 125 | break; 126 | ++Spot; 127 | } 128 | Textures.insert(Spot, pTexture); 129 | } 130 | 131 | void Window::RemoveTexture(Texture* pTexture) 132 | { 133 | pTexture->UpdateEffects(0); 134 | Textures.remove(pTexture); 135 | } 136 | 137 | void Window::MoveCursor(int X, int Y) 138 | { 139 | SDL_WarpMouseInWindow(SDLWindow, X, Y); 140 | } 141 | 142 | void Window::SetFullscreen(Uint32 Flags) 143 | { 144 | SDL_SetWindowFullscreen(SDLWindow, Flags); 145 | } 146 | -------------------------------------------------------------------------------- /src/lexer.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "TextParser.hpp" 4 | #include "Parser.hpp" 5 | #define SAVE_TOKEN xmllval.string = new std::string(yytext, yyleng) 6 | #define TOKEN(t) (xmllval.token = t) 7 | %} 8 | 9 | %option noyywrap 10 | %option prefix="xml" 11 | 12 | %% 13 | 14 | "\n\n" return TOKEN(TNEWLINE); 15 | [ \t\n\r] ; 16 | "PRE" return TOKEN(TPRE); 17 | "RUBY" return TOKEN(TRUBY); 18 | "FONT" return TOKEN(TFONT); 19 | "voice" return TOKEN(TVOICE); 20 | "#"[0-9A-Fa-f]{6} SAVE_TOKEN; return THEX; 21 | [?a-zA-Za-zA-Zあ-ゖァ-ヺ一-龯_@][?,'/.a-zA-Za-zA-Zあ-ゖァ-ヺ一-龯0-90-9_]* SAVE_TOKEN; return TSTRING; 22 | "<" return TOKEN(TLBRACE); 23 | ">" return TOKEN(TRBRACE); 24 | "[" return TOKEN(TLABRACE); 25 | "]" return TOKEN(TRABRACE); 26 | "\"" return TOKEN(TQUOTE); 27 | "=" return TOKEN(TEQUAL); 28 | "/" return TOKEN(TSLASH); 29 | . printf("Unknown token!\n"); yyterminate(); 30 | 31 | %% 32 | -------------------------------------------------------------------------------- /src/parser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "TextParser.hpp" 3 | #include 4 | #include 5 | 6 | extern TextParser::Text* pText; 7 | extern int yylex(); 8 | void yyerror(const char* s) { std::printf("Error: %s\n", s); std::abort(); } 9 | %} 10 | 11 | %union 12 | { 13 | TextParser::StringSegment* strseg; 14 | TextParser::Text* text; 15 | TextParser::Line* line; 16 | TextParser::Voice* voice; 17 | int token; 18 | std::vector* vec; 19 | std::string* string; 20 | } 21 | 22 | %define api.prefix xml 23 | 24 | %token TSTRING THEX 25 | %token TPRE TFONT TRUBY TVOICE TLBRACE TRBRACE TLABRACE TRABRACE TQUOTE TEQUAL TSLASH TNEWLINE 26 | 27 | %type start text 28 | %type line string 29 | %type strseg 30 | %type args voice 31 | %type arg hexarg 32 | 33 | %start start 34 | 35 | %% 36 | 37 | start : TLBRACE TPRE TSTRING TRBRACE TLABRACE TSTRING TRABRACE text TLBRACE TSLASH TPRE TRBRACE { delete $3; delete $6; } 38 | ; 39 | 40 | text : line { $$ = pText; $$->Lines.push_back(*$1); delete $1; } 41 | | text line { $1->Lines.push_back(*$2); delete $2; } 42 | ; 43 | 44 | line : string { $$ = $1; } 45 | | voice string { $$ = $2; $2->VoiceAttrs = *$1; delete $1; } 46 | ; 47 | 48 | string : strseg TNEWLINE { $$ = new TextParser::Line; $$->StringSegs.push_back(*$1); delete $1; } 49 | | strseg string { $$ = $2; $2->StringSegs.push_back(*$1); delete $1; } 50 | ; 51 | 52 | strseg : TSTRING { $$ = new TextParser::StringSegment; $$->Segment = *$1; delete $1; } 53 | | TLBRACE TRUBY arg TRBRACE strseg TLBRACE TSLASH TRUBY TRBRACE { $$ = $5; $5->Ruby = *$3; delete $3; } 54 | | TLBRACE TFONT hexarg hexarg TRBRACE strseg TLBRACE TSLASH TFONT TRBRACE { $$ = $6; $6->InColor = *$3; $6->OutColor = *$4; delete $3; delete $4; } 55 | ; 56 | 57 | voice : TLBRACE TVOICE args TRBRACE { $$ = $3; } 58 | ; 59 | 60 | arg : TSTRING TEQUAL TQUOTE TSTRING TQUOTE { $$ = $4; } 61 | ; 62 | 63 | hexarg : TSTRING TEQUAL TQUOTE THEX TQUOTE { $$ = $4; } 64 | ; 65 | 66 | args : arg { $$ = new TextParser::ArgumentList; $$->push_back(*$1); delete $1; } 67 | | args arg { $1->push_back(*$2); delete $2; } 68 | ; 69 | 70 | %% 71 | --------------------------------------------------------------------------------