310 Commits
Author SHA1 Message Date
Nunuhara Cabbage a55893bf2f debugger: improve print command
Now handles arbitrarily complex member/subscript expressions, with
pretty-printing and a configurable recursion depth.
2023-01-08 17:13:33 -08:00
Nunuhara Cabbage d8f936f1df Implement SystemService.GetGameFolderPath 2023-01-08 11:34:06 -08:00
Nunuhara Cabbage d2539b978e GoatGUIEngine.GetPartsCGName 2023-01-08 11:32:02 -08:00
Nunuhara Cabbage 92bbcb4866 Fix bug in afa_load_archive 2023-01-08 11:30:52 -08:00
Nunuhara Cabbage 96df171157 debugger: clean up help command list
Make the command list printed by the 'help' command easier to read.
2023-01-07 15:28:31 -08:00
Nunuhara Cabbage 9fd0415ec6 debugger: add finish command
Add finish (fin) command which resumes execution until returning from
the current function.
2023-01-07 13:44:08 -08:00
Nunuhara Cabbage 31930c5e97 Use gamedir_path in system.ExistsFile
Fixes an issue where the Sengoku Rance opening movie wouldn't play
if the game was started outside the game directory.
2023-01-07 13:09:49 -08:00
Nunuhara Cabbage def987ad5f debugger: print stack and disassembly side-by-side
This makes the screen position of the disassembly more stable when
stepping through code.
2023-01-07 12:58:09 -08:00
Nunuhara Cabbage a4bb1a815a debugger: show hll function names in disassembly 2023-01-07 10:45:10 -08:00
Nunuhara Cabbage 71f3450037 Only define windows_error_handler on Windows 2023-01-07 10:35:48 -08:00
Nunuhara Cabbage f7c9d9326d debugger: add single-stepping commands
Add 'step' (s) and 'next' (n) commands for single-stepping bytecode.
'step' is the 'step into' type which descends into function calls,
wheras 'next' is the 'step over' type which continues until the next
instruction within the current function.
2023-01-07 09:54:15 -08:00
Nunuhara Cabbage 8b4df9b9a4 Merge pull request #99 from kichikuou/movie
Add error checking for movie format
2023-01-07 08:29:18 -08:00
kichikuou d4d292434c Add error checking for movie format
AliceSoft only uses MPEG-PS, but PlayMovie.dll is included in System4
SDK and can play any format supported by DirectShow. This fixes crash in
movie_load() when given file is not a MPEG-PS.
2023-01-07 18:26:09 +09:00
Nunuhara Cabbage f598a7276b Merge pull request #98 from kichikuou/movie
Implement DrawMovie, DrawMovie2 and PlayMovie HLLs
2023-01-06 18:02:02 -08:00
kichikuou 2f75253080 Add DrawMovie2.{SetInnerVolume,UpdateVolume}
For Rance 02.
2023-01-06 15:21:53 +09:00
kichikuou b0477deca1 Handle events in system.Peek()
Otherwise Sengoku Rance becomes unresponsive during movie playback.
2023-01-06 12:12:10 +09:00
kichikuou de2db1af93 Implement DrawMovie, DrawMovie2 and PlayMovie HLLs
These HLLs play .mpg movie files (later games use .alm file extension,
but the format is the same, i.e. MPEG-PS) that contain MPEG1 video and
MP2 audio streams.

pl_mpeg.h is the PL_MPEG library (https://github.com/phoboslab/pl_mpeg)
imported from commit 5aeef4d07593be1960a0e4c7fe204809cfae30bd.

This adds a few mixer functions (mixer_stream_*) for playing custom
audio streams under the master mixer.
2023-01-06 12:12:07 +09:00
Nunuhara Cabbage b6f9999a56 Merge pull request #96 from kichikuou/repl-on-mbutton
Enter debugger REPL on middle-button click
2023-01-02 16:42:16 -08:00
Nunuhara Cabbage 20b60467f2 Merge pull request #95 from kichikuou/windows-fix
Windows: Fix read_save_file
2023-01-02 16:39:34 -08:00
kichikuou 64a92a2ffa Enter debugger REPL on middle-button click
This is effective only if --debug command line flag is specified.
2023-01-02 21:10:58 +09:00
kichikuou 620fecb244 Windows: Fix read_save_file
This fixes an issue where saved files could not be read on Windows.

On Windows if a file is opened in text mode, ftell() at EOF returns
the file size in bytes, but fread() tries to read the specified number
of characters (after removing carriage returns), resulting in an EOF
error.

To avoid this problem, open save files in binary mode.
2023-01-02 21:00:11 +09:00
Nunuhara Cabbage ca982221f7 Add Windows installation instructions to README
Can now be installed into game directory as sub-directory.
2023-01-01 20:16:33 -08:00
Nunuhara Cabbage 75d8a8b69d Improve usage error reporting
Print usage information when there is an error in the command line
arguments. Also, wait for keypress before exiting on Windows so that the
user can read the error message.
2023-01-01 19:28:59 -08:00
Nunuhara Cabbage 5a5954811f Update libsys4 2023-01-01 13:21:00 -08:00
Nunuhara Cabbage d5b1b155e9 Merge pull request #94 from kichikuou/gles-default
Use OpenGL ES by default
2023-01-01 12:54:51 -08:00
Nunuhara Cabbage 3796521285 Merge pull request #93 from kichikuou/gles
Fix shader compilation errors in OpenGL ES
2023-01-01 12:52:00 -08:00
kichikuou ec5a2c054c Use OpenGL ES by default
This replaces `use_gles` boolean build option with `opengles` feature
option. If OpenGL ES3 is available, it is preferred over desktop OpenGL.
This can be overridden by `-Dopengles=disabled` meson flag.
2023-01-01 13:25:45 +09:00
kichikuou 82407a1d59 Fix shader compilation errors in OpenGL ES 2023-01-01 11:50:03 +09:00
Nunuhara Cabbage e21f06331e Merge pull request #92 from kichikuou/reign
Improve ReignEngine, update game compatibility table
2022-12-28 17:37:45 -08:00
kichikuou d3902470c2 Update game compatibility table
Toushin Toshi 3 is now supported.
2022-12-28 13:51:49 +09:00
kichikuou 68eff9a122 ReignEngine: Fix out-of-bounds access in calc_motion_frame
Happens when frame range in MonsterInfo.txt is wrong.
2022-12-28 13:18:41 +09:00
kichikuou 1edf95bcde ReignEngine: Fix height detection
This fixes an issue where height detection fails due to gaps in
suspension bridge planks.

If the depth map has no value for the given point, return the average
of 4 neighbors.
2022-12-28 13:18:41 +09:00
kichikuou 6e63b4a5e9 ReignEngine: Do not draw particle effect if current_frame == end_frame 2022-12-28 13:18:41 +09:00
kichikuou 9465ee1c63 ReignEngine: Cache parsed motions
Motions are cached in `struct model`.
2022-12-28 13:18:41 +09:00
kichikuou 10710e9908 ReignEngine: Cache parsed particle effects
Now parsed particle-effect definitions are cached in a hash map in the
plugin object. To make it possible, static part of `struct
particle_effect` and `struct particle_object` are factored out to
`struct pae` and `struct pae_object` respectively.
2022-12-28 13:18:41 +09:00
kichikuou defeb0ba17 ReignEngine: Cache loaded models
When there are multiple instances of a model, now they share a single
model object. Model objects are retained in a hash table until the
plugin is released, which is fine because Toushin Toshi 3 doesn't reuse
a plugin across scenes.
2022-12-28 13:18:41 +09:00
Nunuhara Cabbage 9a8e3c59ec Fix use-after-free in font_freetype.c
Pointers to `struct font_size` objects are cached in `struct text_style`
objects, so the `sizes` array can't be reallocated.

This fixes a crash in Rance 02 when entering battle.
2022-12-27 10:14:14 -08:00
Nunuhara Cabbage f23d713f46 Merge pull request #91 from kichikuou/effect
Implement EFFECT_NOISE_CROSSFADE and EFFECT_SEPIA_NOISE_CROSSFADE
2022-12-27 10:11:54 -08:00
Nunuhara Cabbage 1f84f33346 Merge pull request #90 from kichikuou/reign
ReignEngine improvements
2022-12-27 10:11:27 -08:00
kichikuou 8aafb271f9 Implement EFFECT_NOISE_CROSSFADE and EFFECT_SEPIA_NOISE_CROSSFADE
EFFECT_SEPIA_NOISE_CROSSFADE is frequently used in Toushin Toshi 3.
2022-12-27 21:13:01 +09:00
kichikuou c7cebb9ea9 ReignEngine: Fix out-of-range material index in .POL
Without this, some maps (e.g. map059) and battle backgrounds
(e.g. bg101) in Toushin Toshi 3 are not rendered correctly.
2022-12-24 16:54:41 +09:00
kichikuou 2de5132803 ReignEngine: Support (sprite) mesh attribute
It has the same effect as the (sprite) material attribute.

Also, now sprite objects are rendered in the DRAW_OPAQUE phase.
2022-12-24 16:54:40 +09:00
kichikuou 70b4071350 ReignEngine: Support "shadow darkness" material parameter
It is a value between 0.0 and 1.0, where 0.0 means no shadows are drawn
on the material.
2022-12-24 16:54:40 +09:00
kichikuou eb13ae0cc1 ReignEngine: Fix rendering issue of skinned models without motion
This fixes a bug where skinned instances with no motion loaded were not
drawn.
2022-12-24 16:54:40 +09:00
kichikuou 06b9da800c Implement ReignEngine.SetInstanceDebugDrawShadowVolume
It visualizes the bounding sphere of the instance. Although it is only
called from dead code in Toushin Toshi 3, it's useful for debugging
shadow mapping.
2022-12-24 16:54:37 +09:00
kichikuou fdd0af8dcf ReignEngine: Improve shadow view-frustum calculation
This fixes broken shadow rendering e.g. when Nacht climbs a ladder.

Now update_bones() calculates the instance's bounding sphere which
is the minimum sphere containing the AABB of current bone coordinates.
This corresponds to the sphere that is displayed when calling
SetInstanceDebugDrawShadowVolume on the original ReignEngine.dll.
2022-12-24 16:25:05 +09:00
Nunuhara Cabbage cfaed35f23 Merge pull request #89 from kichikuou/half-width
font_freetype: Fix display width of half-width kana and some symbols
2022-12-21 18:52:05 -08:00
Nunuhara Cabbage f2f5391ae8 Merge pull request #88 from kichikuou/DrawMovie
Add stubs for DrawMovie library
2022-12-21 18:51:16 -08:00
kichikuou 1bcf026f25 font_freetype: Fix display width of half-width kana and some symbols
Halfwidth katakana are now displayed in half-width.

This also fixes an issue where some symbols with codepoint <256 (e.g.
MULTIPLICATION SIGN) were considered half-width, while the bundled font
has full width glyphs for those codepoints.
2022-12-18 14:57:04 +09:00
kichikuou acb814021c Add stubs for DrawMovie library
Used in Toushin Toshi 3. The interface is the same as DrawMovie2.
2022-12-18 10:27:34 +09:00
Nunuhara Cabbage de7cbf1c1e Merge pull request #87 from kichikuou/reign
ReignEngine improvements
2022-12-16 21:53:33 -08:00
kichikuou 8c72c5b5e0 ReignEngine: Normalize vectors after applying normal_transform
normal_transform can be non-orthogonal, so after transforming with it
direction vectors must be normalized.

This fixes a bug where President Garter is rendered too specular.
2022-12-17 10:59:16 +09:00
kichikuou 9a6553f215 ReignEngine: Fix glTexImage2D arguments for shadow renderer
GL_DEPTH_COMPONENT is not a valid value for internalFormat in OpenGL ES.
2022-12-17 10:59:16 +09:00
kichikuou 3ef252c68b ReignEngine: Improve z-sorting
This fixes billboard rendering issue in some dungeons.

* For polygon models, use its AABB's center coordinates.
* Consider the camera angle, i.e. sort by view-space Z-coordinate
  instead of world-space Z-coordinate.
2022-12-17 10:59:16 +09:00
kichikuou 6cc0bd7cb4 ReignEngine: Implement (both) mesh attribute
I'm not sure what it means exactly, but at least it disables shadow
drawing (but does not disable shadow casting).
2022-12-17 10:59:16 +09:00
kichikuou 02b0c8c80c ReignEngine: Implement (nomakeshadow) mesh attribute 2022-12-17 10:59:16 +09:00
Nunuhara Cabbage a0f4f9a4ab Merge pull request #86 from kichikuou/effect
Implement EFFECT_TV_SWITCH_ON
2022-12-11 16:42:37 -08:00
kichikuou 86bee21a9d Implement EFFECT_TV_SWITCH_ON
Used in Toushin Toshi 3.
2022-12-11 21:48:02 +09:00
Nunuhara Cabbage 4897dbf3c7 Merge pull request #85 from kichikuou/reign
ReignEngine improvements
2022-12-10 13:42:57 -08:00
kichikuou b79eb9ccea ReignEngine: Do not WARNING() on SetBackCGName("")
It just unloads current CG.
2022-12-10 11:34:34 +09:00
kichikuou 408f35f4ec Fix ReignEngine.SetInstanceScaleZ 2022-12-10 11:26:14 +09:00
kichikuou 5b9e7ac7e4 ReignEngine: Correctly mark transparent materials
There are two types of transparent materials: materials that have an
alpha map and materials that have a color map with an alpha channel.
This change makes the latter to be considered transparent.
2022-12-10 11:25:42 +09:00
kichikuou c5b0122d72 ReignEngine: Use glDepthFunc(GL_LEQUAL) when drawing billboards
So that multiple billboards overlapping on a plane are rendered
correctly.
2022-12-10 11:24:38 +09:00
Nunuhara Cabbage 0d83bce07d Merge pull request #84 from kichikuou/R_NOTE
Implement R_NOTE instruction
2022-12-04 07:52:41 -08:00
kichikuou f78013b70b Implement R_NOTE instruction
It corresponds to the !== operator.
2022-12-04 17:14:19 +09:00
Nunuhara Cabbage 592e7c3f9f Merge pull request #83 from kichikuou/data-hll
Implement Data.hll
2022-12-03 22:54:09 -08:00
kichikuou f152f41d0a Implement Data.hll
No AliceSoft game uses this, but it's included in the System4 SDK and
used by some indie games.
2022-12-03 09:47:16 +09:00
Nunuhara Cabbage 7aaa19404c Merge pull request #82 from kichikuou/mmap
Do not use ARCHIVE_MMAP on 32-bit systems
2022-11-26 20:34:01 -08:00
kichikuou 6efa31454d Do not use ARCHIVE_MMAP on 32-bit systems
Some games have assets that are too large to mmap everything on a 32-bit
address space. For example, TT3 has a total of 2.82GB of assets, which
is too large for the 3GB address space limit of 32-bit Linux. On Android
it's even stricter and mmaps of hundreds of MB can fail.
2022-11-26 22:29:57 +09:00
Nunuhara Cabbage 31e91cc3ad Merge pull request #81 from kichikuou/font
font_freetype: Consider glyph information for horizontal positioning
2022-11-24 19:25:08 -08:00
Nunuhara Cabbage b9637a59ff Merge pull request #80 from kichikuou/drawtype
ReignEngine: Implement {Get,Set}InstanceDrawType
2022-11-24 19:16:50 -08:00
kichikuou 638de2057a font_freetype: Consider glyph information for horizontal positioning
When creating a block-sized texture from a glyph, use the bitmap_left
field of FT_GlyphSlot instead of just centering it horizontally.

This improves positioning of punctuation marks in Japanese text.
2022-11-20 12:02:18 +09:00
kichikuou 28f95bfe38 ReignEngine: Implement {Get,Set}InstanceDrawType
Billboards of draw type 1 are drawn with additive blending.
2022-11-20 09:47:10 +09:00
Nunuhara Cabbage c296ca1682 Merge pull request #79 from kichikuou/cursor
Implement Cursor.Set HLL function
2022-11-19 08:32:59 -08:00
kichikuou 33760da0fa Implement Cursor.Set HLL function
In Toushin Toshi 3, it is used only to show / hide the mouse cursor.
2022-11-19 21:46:11 +09:00
Nunuhara Cabbage 36d2216e66 Merge pull request #78 from kichikuou/reign
ReignEngine: Per-mesh control of drawing order
2022-11-16 20:20:56 -08:00
kichikuou 00d1d01353 ReignEngine: Per-mesh control of drawing order
Before this, the order of drawing was determined on an instance-by-
instance basis. Instances with even a single transparent material were
drawn after fully opaque instances.

After this, first the opaque meshes in all instances are drawn, and then
the transparent meshes are drawn from the nearest to the farthest.
2022-11-13 14:20:31 +09:00
Nunuhara Cabbage a3e3232825 Update libsys4 2022-11-11 20:28:45 -08:00
Nunuhara Cabbage eec9663145 Merge pull request #77 from kichikuou/tt3
ReignEngine improvements
2022-11-09 16:37:53 -08:00
kichikuou 5f17dafdf8 ReignEngine: Set correct initial value for fog parameters
This fixes rendering issue of the model viewer in Alice's Mansion.
2022-11-05 22:17:38 +09:00
kichikuou 581593f9b5 ReignEngine: Support (env) mesh attribute
If specified, the mesh should be rendered with environment mapping
using the material's COLOR_MAP as a matcap texture.
2022-11-05 20:56:26 +09:00
kichikuou 241f631d9d ReignEngine: Set loop frame range for particle effects
Without this, update_motion cannot calculate current_frame correctly
when the effect is used with RE_MOTION_STATE_LOOP state.
2022-11-05 20:56:26 +09:00
kichikuou 814ebb7d3d ReignEngine: Support (sprite) material attribute
If specified, alpha test is used instead of alpha blend.
2022-11-05 20:56:25 +09:00
kichikuou 1a9a2e9753 ReignEngine: Support (nolighting) mesh attribute
In ReignEngine, the mesh name field may contain keywords that change
rendering behavior. The "(nolighting)" keyword disables lighting and
fog.
2022-11-05 20:56:25 +09:00
kichikuou 31823f5731 ReignEngine: Draw instances in z-order
To get correct blending effect for overlapped transparent objects.
2022-11-05 20:56:25 +09:00
Nunuhara Cabbage 835679205c Merge pull request #76 from kichikuou/overflow
Fix integer overflow in audio_mixer.c
2022-10-22 09:30:22 -07:00
kichikuou 88268b084c Fix integer overflow in audio_mixer.c
This fixes a bug in Toushin Toshi 3 where the audio thread crashes when
battle ended, after exploring the second dungeon for (INT_MAX / 44100)
milliseconds (~= 50 secs).
2022-10-22 10:23:22 +09:00
Nunuhara Cabbage 76aba9cd6b Merge pull request #75 from kichikuou/tt3
Fixes / improvements for Toushin Toshi 3
2022-10-12 20:05:20 -07:00
kichikuou 2370052b54 ReignEngine: Fix bone mapping between model and motion
Some motion files (e.g. maidsan_ahoge_* and otokomae_*) have wrong bone
IDs, so bone names should be used to look up matching bones in the
model.

However, this does not always work because masokan.POL has multiple
bones with the same name. In that case ID matching must be used.
2022-10-10 14:20:20 +09:00
kichikuou 252f1b5464 Fix out-of-bounds access in MsgSkip HLL
Toushin Toshi 3 calls MsgSkip.{Get,Set}Flag with msgnum = -1.
2022-10-10 14:20:20 +09:00
kichikuou 5c288f87e5 Implement EFFECT_TV_SWITCH_OFF
Used in Toushin Toshi 3.
2022-10-10 14:20:20 +09:00
Nunuhara Cabbage 0dec3ff5eb Merge pull request #74 from kichikuou/gles
Fix text rendering issue in OpenGL ES
2022-10-03 21:54:32 -07:00
kichikuou 3f1d76cd9f Fix text rendering issue in OpenGL ES
This fixes an issue where text is not rendered on Android.

In OpenGL ES3.0, GL_RED is not a valid value for the internalFormat
parameter of glTexImage2D.
2022-10-03 21:59:30 +09:00
Nunuhara Cabbage bc852567f2 Merge pull request #73 from kichikuou/gles
Fix shader compilation errors in OpenGL ES
2022-10-01 10:37:52 -07:00
Nunuhara Cabbage 11356db636 Merge pull request #72 from kichikuou/reign
ReignEngine improvements
2022-10-01 10:34:19 -07:00
kichikuou 1ae812ff03 Fix shader compilation errors in OpenGL ES 2022-10-01 16:41:51 +09:00
kichikuou 3615223b52 ReignEngine: Implement alpha mapping 2022-10-01 16:24:20 +09:00
kichikuou fbf74db7a4 ReignEngine: Fix rim lighting for very small rim_exponent values 2022-10-01 16:24:16 +09:00
kichikuou 773cce03eb ReignEngine: Implement camera quake effect 2022-10-01 16:24:13 +09:00
Nunuhara Cabbage 8d0cf7cdcb Merge pull request #71 from kichikuou/particle
ReignEngine: Implement particle rendering
2022-09-26 17:04:34 -07:00
kichikuou 97c65a33db Add frame bounds check in render_polygon_particles() 2022-09-26 15:46:12 +09:00
kichikuou 909168acdb ReignEngine: Implement particle rendering
This completes the implementation of the particle effect system, except
for the camera quake effect.
2022-09-25 10:39:37 +09:00
Nunuhara Cabbage 296fe887e5 Merge pull request #70 from kichikuou/reign
ReignEngine improvements
2022-09-11 09:52:32 -07:00
kichikuou 803bb1a8a4 ReignEngine: Fix BackCG issues
- Enable both alpha map and alpha mod, using the new drawing function
  gfx_copy_stretch_blend_amap_alpha().
- Do not draw if `bcg->show` flag is false.
- Do not WARNING() for SetBackCGNum(0) as it's used to unload the CG.
2022-09-11 21:08:54 +09:00
kichikuou c30225d535 ReignEngine: Bind all vertex attributes to fixed locations
So that model_load() doesn't have to depend on RE_renderer.
2022-09-11 14:39:37 +09:00
kichikuou 2ceb727a66 ReignEngine: Instances with draw=false should not cast shadows 2022-09-11 14:35:50 +09:00
kichikuou 7bffaeffe6 ReignEngine: Fix projection matrix calculation
Now it makes the same angle of view as the original ReignEngine.
2022-09-11 14:33:43 +09:00
Nunuhara Cabbage 57525689a2 Merge pull request #69 from kichikuou/particle
ReignEngine: Add loader for particle effects
2022-09-04 15:21:41 -07:00
kichikuou 0ff9c5a62c ReignEngine: Add loader for particle effects
This implements a parser for particle effect definition files (.pae)
and a set of field accessor functions for the RE_ITYPE_PARTICLE_EFFECT
instance type. Rendering of effects is not yet implemented.
2022-09-04 10:17:03 +09:00
Nunuhara Cabbage 30b810b309 Merge pull request #68 from kichikuou/fog
ReignEngine: Implement Fog
2022-08-05 18:51:38 -07:00
kichikuou 06a630ea62 ReignEngine: Implement Fog
There are two types of fog, linear fog and atmospheric scattering. The
formula for light scattering is incorrect (see the comment in
reign.v.glsl) and therefore not physically correct.
2022-08-06 09:38:48 +09:00
Nunuhara Cabbage 3e536af09a Implement DG_ADD, DG_EXIST, DG_ERASE 2022-08-02 18:16:16 -07:00
Nunuhara Cabbage 62a2dc003c Merge pull request #67 from kichikuou/height
ReignEngine: Implement CalcInstanceHeightDetection
2022-07-30 12:55:59 -07:00
kichikuou d185ae71bf ReignEngine: Implement CalcInstanceHeightDetection
This is used to compute Y-positions of map objects.

It is called quite often, so this implementation creates and caches a
height map of the instance by (re)using the shader for shadow mapping.
2022-07-30 15:17:08 +09:00
Nunuhara Cabbage be977bab46 Merge pull request #66 from kichikuou/shadow
ReignEngine: Implement shadow mapping
2022-07-24 14:04:50 -07:00
kichikuou 233b2a4f20 ReignEngine: Implement shadow mapping 2022-07-24 16:01:16 +09:00
kichikuou b0e540e67b gfx: Expose low level shader loading function
And use it in 3d/. This gives more flexibility on vertex attribute /
uniform variable configurations.
2022-07-24 16:01:16 +09:00
Nunuhara Cabbage 9675c8f256 Merge pull request #65 from kichikuou/3d
ReignEngine improvements
2022-07-23 11:27:15 -07:00
kichikuou 2918a6310c ReignEngine: Remove hard limit on number of instances
Some maps in Toushin Toshi 3 have more than 32 instances.
2022-07-23 21:41:41 +09:00
kichikuou fc81d0ec4e ReignEngine: Do not ignore BuildModel() with elapsed time 0
It isn't no-op, because instance motion may be changed by
SetInstanceMotionFrame().
2022-07-23 21:23:13 +09:00
kichikuou e7c9410df4 ReignEngine: Implement two functions
GetInstanceBoneIndex and TransInstanceLocalPosToWorldPosByBone.
2022-07-18 13:01:49 +09:00
Nunuhara Cabbage feb2fc17f4 Merge pull request #64 from kichikuou/BuildModel
Implement ReignEngine.BuildModel
2022-07-17 16:29:23 -07:00
kichikuou 3343efbcb9 Implement ReignEngine.BuildModel
Instance motions are updated with this function.
2022-07-17 16:20:02 +09:00
Nunuhara Cabbage b1f3e85c4d Merge pull request #63 from kichikuou/lighting
ReignEngine: Implement bump mapping and light mapping
2022-07-16 11:15:01 -07:00
kichikuou af7127580c ReignEngine: Implement light mapping 2022-07-16 15:26:41 +09:00
kichikuou 84f55a55cd ReignEngine: Optimize vertex buffer layout
Now unused vertex attributes (e.g. bone weights) are not included in the
vertex buffer.
2022-07-16 15:26:38 +09:00
kichikuou c86ca5de87 ReignEngine: Implement bump mapping 2022-07-16 12:59:35 +09:00
Nunuhara Cabbage b98fff601f Merge pull request #62 from kichikuou/lighting
ReignEngine: Implement rim lighting and specular mapping
2022-07-10 21:47:49 -07:00
kichikuou 80c6b62074 ReignEngine: Implement specular map 2022-07-10 13:33:50 +09:00
kichikuou fe02c8f401 ReignEngine: Implement rim lighting
Lighting parameters are per-material and are stored in the .amt file.
2022-07-10 13:20:50 +09:00
Nunuhara Cabbage 2e23554162 Implement SACT2.Joypad_GetAnalogStickStatus 2022-07-09 17:35:07 -07:00
Nunuhara Cabbage 6ed2417612 Merge pull request #61 from kichikuou/billboard
ReignEngine: Fix billboard rendering issue
2022-07-09 17:22:40 -07:00
kichikuou 5e25dd4000 ReignEngine: Fix billboard rendering issue
This fixes an issue where billboard objects are not drawn in some
environments.

ReignEngine disables some vertex attributes when drawing billboards, but
AMD's driver doesn't draw anything if any of those attributes are
assigned to attribute index 0.

To avoid this, this explicitly binds "vertex_pos" attribute (which is
always enabled) to index 0.

References:
https://community.khronos.org/t/gldisablevertexattribarray-not-working/67077/4
https://stackoverflow.com/questions/28818997/how-to-use-glvertexattrib
2022-07-10 08:04:08 +09:00
Nunuhara Cabbage b39ad5fdc3 Merge pull request #60 from kichikuou/lighting
ReignEngine: Implement basic lighting
2022-07-09 08:28:34 -07:00
kichikuou b42032c9f8 ReignEngine: Implement basic lighting
This implements a Phong shading with ambient, diffuse and specular
components, using up to three directional lights and one specular light.

The light calculation is made to match the "high quality" 3D mode of
Toushin Toshi 3.
2022-07-09 14:36:44 +09:00
kichikuou b23d05bcc2 ReignEngine: Load material parameters from .amt file 2022-07-09 14:36:40 +09:00
Nunuhara Cabbage 8b6d4943b3 Implement SH_A_FIND_SREF
Used in Rance 01.
2022-06-26 20:41:56 -07:00
Nunuhara Cabbage a78f5348f3 Fix memory leak in PassRegister 2022-06-26 20:15:52 -07:00
Nunuhara Cabbage 73b21210c2 Fix delegate memory management issues
Delegates should be ref'd in vm_copy and unref'd in variable_fini.

This also includes some improvements to the diagnostic reporting of
DEBUG_HEAP.
2022-06-26 17:55:05 -07:00
Nunuhara Cabbage be2b1421f1 Merge pull request #59 from kichikuou/Toushin3Loader
Toushin3Loader: Fix use-after-free after VM reset
2022-06-26 08:26:33 -07:00
kichikuou 60e9696a23 Toushin3Loader: Fix use-after-free after VM reset 2022-06-26 21:15:59 +09:00
Nunuhara Cabbage 9f42ee379d Improve performance of vm_image_to_json
Use a callback-based function to create the heap JSON array. This avoids
the O(n) insertion time of cJSON_AddItemToArray.
2022-06-25 10:00:24 -07:00
Nunuhara Cabbage 3a40542aab parts: fix bug with INT_MIN in numeral object
Use 64-bit integer to avoid overflow when creating numeral for INT_MIN.
2022-06-25 09:22:11 -07:00
Nunuhara Cabbage 841947d544 Fix delegate memory management and FT_ASSIGNS
Each delegate call needs to copy its arguments so that they aren't
double-freed by the next call.

Also fix a bug in FT_ASSIGNS where -1 was returned for non-existant
functions instead of 0.
2022-06-25 09:20:22 -07:00
Nunuhara Cabbage c14e7bd218 Ignore extension in asset_get_by_name
Fixes bug when starting battle in Rance 01.
2022-06-24 18:40:36 -07:00
Nunuhara Cabbage 96f307838f Merge branch 'master' of github.com:nunuhara/xsystem4 2022-06-24 18:02:14 -07:00
Nunuhara Cabbage fc42c42ef5 parts: refactor parent-child handling
Parent-child relationships are established by the UpdateComponent
function. Parts_SetParentPartsNumber does not establish the relationship
(and it does not create the parent object if it does not exist yet).

Render params are now computed recursively on children when they are set
on the parent (instead of recomputing them every time a child parts is
rendered).
2022-06-24 17:54:25 -07:00
Nunuhara Cabbage 8ee136b287 parts: various fixes and improvements
* SetAddColor and SetMultiplyColor implemented
* additive draw filter implemented
* GetPartsUpperLeftPos{X,Y} implemented
* various parameters are now applied from parent to child parts
* misc. bug fixes

The first dungeon screen in Rance 01 now renders correctly.
2022-06-21 19:57:36 -07:00
Nunuhara Cabbage 37cd4ac179 Fix save/resume issue with delegate pages 2022-06-19 16:52:08 -07:00
Nunuhara Cabbage 57b93839be parts: fix render order (again)
The render order is determined by the sum of the parts' z-value and the
z-values of its parents.
2022-06-19 15:42:00 -07:00
Nunuhara Cabbage ed31e25a38 Merge pull request #58 from kichikuou/billboard
ReignEngine: Support billboard instance type
2022-06-19 08:44:04 -07:00
kichikuou d11116f647 ReignEngine: Support billboard instance type
Used for 2D objects (e.g. NPCs in dungeons).
2022-06-19 12:19:41 +09:00
kichikuou 3851dc7c6a ReignEngine: Add RE_instance_type enum
This is in preparation for supporting non-polygon instance types.
2022-06-19 11:51:13 +09:00
Nunuhara Cabbage 25695c3e86 parts: implement GUIEngine numerals
Implement Parts_SetNumeralLinedCGNumberWidthWidthList and
Parts_SetNumeralLength.

Also fix bugs where changing numeral properties would not update the
texture until the number was reset.
2022-06-18 10:53:43 -07:00
Nunuhara Cabbage e1872edb5a parts: fix render order of child parts
The parent's z-value determines the render order of its children.

Alicesoft's implementation of this is a bit weird. The render order only
changes when the parent's visibility is toggled (via Parts_SetShow), NOT
when the parent is set on a child or the parent's z-value changes.

I have chosen to implement this so that the render order is always based
on the current parent/child z-values.

This fixes some bugs in Rance 01.
2022-06-18 09:11:28 -07:00
Nunuhara Cabbage 7ecbc808c6 Merge pull request #57 from kichikuou/backcg
ReignEngine: Implement background CG functions
2022-06-17 19:44:04 -07:00
kichikuou 1568d63117 ReignEngine: Implement background CG functions
This also moves debug print functions to a separate file.
2022-06-18 10:32:49 +09:00
Nunuhara Cabbage 790502c51f Merge branch 'master' of github.com:nunuhara/xsystem4 2022-06-17 17:02:42 -07:00
Nunuhara Cabbage ad83a0cd39 Fix ChipmunkSpriteEngine.SP_GetFontWidth
Use gfx_size_text. Fixes text layout issue in Rance 01.
2022-06-17 16:54:14 -07:00
Nunuhara Cabbage a6913af2bc parts: implement more ConstructionProcess ops
Implement Fill, FillAMap, DrawCutCG and CopyCutCG operations.
2022-06-17 16:08:30 -07:00
Nunuhara Cabbage 8ff4fa8666 parts: various fixes and improvements
The title screen in Rance 01 now functions as expected.
2022-06-16 19:13:36 -07:00
Nunuhara Cabbage ced0a832cc Implement ChipmunkSpriteEngine.Sleep 2022-06-16 09:47:26 -07:00
Nunuhara Cabbage e68ff819de fnl: adjust for edge width in layout
Account for the edge width when doing text layout in games that use .fnl
fonts (except for the MangaGamer version of Sengoku Rance).
2022-06-14 20:51:34 -07:00
Nunuhara Cabbage bbe8b4053f Implement CommonSystemData library
Except for the LoadAtStartup function.
2022-06-14 20:41:51 -07:00
Nunuhara Cabbage 554d9708da Merge pull request #56 from kichikuou/MonsterInfo
MonsterInfo: Fix SEGV, clean up
2022-06-13 16:32:43 -07:00
kichikuou 7effe8920a MonsterInfo: Fix SEGV, clean up
Fixes a crash bug when attempted to get a string property of nonexistent
motion.

This also fixes compiler warnings, and simplifies the code by using
helper functions.
2022-06-13 20:54:59 +09:00
Nunuhara Cabbage 20d5820efc parts: add PARTS_UNINITIALIZED parts type 2022-06-12 19:23:02 -07:00
Nunuhara Cabbage e78119bf5a parts: refactor pos/size handling
Move position/size values around and rename them to reflect what they
actually mean:

* parts->offset moved to parts_common->origin_offset
* parts->pos moved to parts_common->hitbox
* x and y coordinates from parts->rect renamed to parts->pos
* width and height from parts->rect moved into parts_common
2022-06-12 19:03:41 -07:00
Nunuhara Cabbage b60cce3e8f parts: handle zero surface area at render time
Check for uninitialized or explicitly zeroed surface area at render
time. This fixes an issue where some construction process parts would
not be rendered (specifically, the button text on the Rance 01 title
screen).
2022-06-12 14:44:08 -07:00
Nunuhara Cabbage d79020656c debugger: command modules
Allow adding groups of commands to the debugger at run time. This is
currently used only by GUIEngine.
2022-06-12 14:29:46 -07:00
Nunuhara Cabbage 49774fa4b6 Merge pull request #55 from kichikuou/SetInstanceAlpha
Implement ReignEngine.SetInstanceAlpha
2022-06-12 09:41:07 -07:00
kichikuou db97942393 Implement ReignEngine.SetInstanceAlpha 2022-06-12 21:27:49 +09:00
Nunuhara Cabbage 06949f59e8 Merge pull request #54 from kichikuou/motion
ReignEngine: Implement skeletal animation
2022-06-11 20:24:00 -07:00
kichikuou 315c7e6a50 Fix memory leaks in RE_instance_load_{,next_}motion 2022-06-12 08:52:44 +09:00
kichikuou 442ebce079 Add debug_print method to draw_plugin
Plugins can implement this so that scene_print will print additional
information for the sprite. RE_plugin implements this to dump the 3D
scene information.
2022-06-11 13:43:59 +09:00
kichikuou a2bbe15b20 ReignEngine: Implement skeletal animation 2022-06-11 13:28:02 +09:00
Nunuhara Cabbage caec854ed8 Implement scene_print function
Add a scene_print function which prints a textual representation of the
current scene. This works by attaching a `debug_print` function to each
entity in the scene. This function is implemented for SACT2 and
GUIEngine entities. A default implementation will be used of none is
provided.

This can be accessed from the debugger via the `scene` command (although
the output is typically too much to view in a terminal; it's better to
run `scene_print` somewhere and redirect stdout to a file).
2022-06-10 19:18:10 -07:00
Nunuhara Cabbage 7e04db958b parts: implement more ConstructionProcess ops
Implement Create, CreatePixelOnly, DrawText and CopyText operations.
2022-06-10 15:28:08 -07:00
Nunuhara Cabbage 1484a207c5 Implement GUIEngine.{Set,Get}DelegateIndex 2022-06-08 17:09:47 -07:00
Nunuhara Cabbage 09f2c3e1ed parts: implement Parts_Set*SurfaceArea functions
These functions apply a clipping rectangle to the parts texture.
2022-06-08 16:51:06 -07:00
Nunuhara Cabbage 7205570611 parts: make construction process a parts type 2022-06-07 16:25:00 -07:00
Nunuhara Cabbage 7223d4d6aa Fix bug in afa_get_by_id
Fix bug where asset_get would return unloaded files from afa archives.
2022-06-06 18:18:17 -07:00
Nunuhara Cabbage eaa0baad7f Handle library incompatibilities
Add a mechanism for libraries to resolve incompatibilities between
library versions before linking.

This is currently used for ChipmunkSpriteEngine and GoatGUIEngine,
where early versions used integer IDs when loading CGs (later versions
use strings).
2022-06-06 08:49:12 -07:00
Nunuhara Cabbage 19ac7e6935 Refactor asset_manager (again)
There are now two types of asset management:
    1. ID-indexed assets, where IDs are not necessarily sequential
    2. name-indexed assets

Name-indexed assets can have additional archives added at run-time. This
is to support the CGManager.LoadArchive function used in Rance Quest
Magnum.

Name-indexed assets always use .afa archives. ID-indexed assets mostly
use .ald archives, except for Daiteikoku and Shaman's Sanctuary.

asset_get_by_name is now case insensitive and ignores the file
extension.
2022-06-05 19:15:41 -07:00
Nunuhara Cabbage 7eb620aca7 Refactor asset_manager
asset_exists and asset_get now take 1-indexed IDs.

Custom CG indexing code for Shaman's Sanctuary is now removed and
replaced with a proper implementation of afa v1 archives in libsys4.
2022-06-05 12:26:18 -07:00
Nunuhara Cabbage e21111bc5f Merge pull request #53 from kichikuou/fillangle
Implement FillAngle HLL
2022-06-04 21:11:04 -07:00
kichikuou 9da9f53671 Implement FillAngle HLL
This is used in Toushin Toshi III for the "clock" effect of battle
command icons.
2022-06-05 10:06:42 +09:00
Nunuhara Cabbage 53b61fa69b Merge pull request #52 from kichikuou/3d
Initial implementation of ReignEngine HLL
2022-06-03 21:51:42 -07:00
kichikuou dca30c3aab Initial implementation of ReignEngine HLL
ReignEngine is the 3D rendering engine used in Toushin Toshi III, and is
the predecessor of the 3D engines for Rance Quest, Rance 9, Evenicle,
etc.

This implements minimal functionality to be able to draw the first 3D
dungeon scene. Many important parts such as motion and lighting are not
implemented yet.
2022-06-04 11:29:07 +09:00
Nunuhara Cabbage afc7665dc8 Merge pull request #51 from kichikuou/cglm
Update cglm to v0.8.5
2022-06-03 16:47:15 -07:00
kichikuou 7d7bc00765 Update cglm to v0.8.5 2022-06-04 08:26:45 +09:00
Nunuhara Cabbage 9f7cc44949 Merge pull request #49 from kichikuou/plugin
Introduce draw_plugin
2022-05-31 16:31:13 -07:00
kichikuou 81ff379eb8 Avoid iterating over the scene for plugins update
Now plugin is a member of sact_sprite, and sprite.c manages a list of
sprites with plugins.
2022-05-31 18:13:08 +09:00
kichikuou fd4cd139f8 Introduce draw_plugin
This introduces draw_plugin struct that can be attached to a sprite.
The update() function of attached plugin is called every frame by
sact_Update(). This corresponds to the DrawPlugin mechanism of
System4/SACT2.

This is currently used only from DrawDungeon. The 3D engine for Toushin
Toshi 3 etc. will also use this.
2022-05-30 11:41:20 +09:00
Nunuhara Cabbage 7be684e9bf Merge pull request #48 from kichikuou/tt3
Add HLL implementations for Toushin Toshi III
2022-05-28 09:23:33 -07:00
kichikuou e1268262fc Add stubs for SACTDX and SystemService functions
For Toushin Toshi III.
2022-05-28 13:09:38 +09:00
kichikuou ce8d9aaf65 Implement File2 HLL library
For Toushin Toshi III.
2022-05-28 13:09:38 +09:00
kichikuou 696601abcf Implement Toushin3Loader HLL library 2022-05-28 13:09:38 +09:00
kichikuou 941cb71a49 Implement MonsterInfo HLL
For Toushin Toshi III.
2022-05-28 13:09:35 +09:00
kichikuou 9c76a24d01 Add stubs for Confirm3 and Cursor HLLs 2022-05-22 21:02:34 +09:00
Nunuhara Cabbage 7dc4898a21 Fix outline cutoff issue with .fnl fonts 2022-05-15 09:54:10 -07:00
Nunuhara Cabbage 1fd475813d Remove unused headers 2022-05-15 09:23:11 -07:00
Nunuhara Cabbage 9b83a6d09d Refactor text rendering code
.fnl fonts can now be used outside of SengokuRanceFont, and
SengokuRanceFont now uses the same text layout and caching code as
SACT2, etc.
2022-05-14 23:12:36 -07:00
Nunuhara Cabbage 128edda6c0 text: fix outline cropping issue
Fix issue where outlines would get cropped when crossing the glyph
texture boundary.

This is accomplished by adding 4 border pixels to each glyph texture.
2022-05-10 19:53:31 -07:00
Nunuhara Cabbage 6070f702fa Add option to override save folder location
The `--save-folder` command line option, or `save-folder` option in
.xsys4rc, can be used to override the default save folder location.

This is useful in cases where English and Japanese versions of the same
game share a save location, or to isolate saves from a mod, etc.
2022-05-08 17:28:01 -07:00
Nunuhara Cabbage 8068992244 Document FreeType dependency in README 2022-05-08 17:27:45 -07:00
Nunuhara Cabbage 191bde690d Merge branch 'master' of github.com:nunuhara/xsystem4 2022-05-08 16:28:26 -07:00
Nunuhara Cabbage 2262f7067c Use FreeType2 instead of SDL_ttf
SDL_ttf isn't really designed to be used with OpenGL. It caches glyph
bitmaps in memory, whereas we want to cache glyph textures on the GPU.
By using FreeType directly we avoid creating and destroying a new
texture every time a glyph is rendered.

Additionally, all glyph textures (including fnl-derived glyphs) now use
the GL_RED internal format instead of GL_RGBA.
2022-05-08 16:11:25 -07:00
Nunuhara Cabbage c09836e551 Use sprite draw method/blend rate for text also 2022-05-08 13:52:16 -07:00
Nunuhara Cabbage a7ca9430e8 Merge pull request #47 from kichikuou/datetime
Fix date/time getter functions
2022-05-07 22:59:18 -07:00
kichikuou 03f23c4339 Fix date/time getter functions
Values returned by SACT2.System_GetDate etc. should correspond to the
Windows SYSTEMTIME structure, not struct tm.

This also fixes a bug where get_time() returns a value greater than 60
for `sec`.
2022-05-08 14:20:45 +09:00
Nunuhara Cabbage 39ce914bf9 Optimize error checks in hot functions
Use `unlikely` (__builtin_expect) to help the compiler optimize error
checks in some hot functions (in my testing, stack_pop_var was one of
the hottest functions, right behind execute_instruction).
2022-05-06 20:43:30 -07:00
Nunuhara Cabbage 0b98e57938 Don't decode little endian on x86/x86_64 2022-05-06 19:27:30 -07:00
Nunuhara Cabbage b499c432fd Update game compatibility table
MangaGamer version of Sengoku Rance is now supported.
2022-05-05 21:11:25 -07:00
Nunuhara Cabbage fa4cdc81d0 Use gfx_draw_glyph for SACT2 (etc.) text rendering
This greatly improves the look of outlines, especially at larger font
sizes (such as in Haruurare).
2022-05-05 18:12:18 -07:00
Nunuhara Cabbage 0b52a4baa0 Fix issue with text blend mode
The source alpha was being multiplied by itself, making text look
thinner than it should. Now we just take the max alpha.
2022-05-05 18:09:51 -07:00
Nunuhara Cabbage 6080af3621 Implement Sound_GetGroupNumFromDataNum
Part of StoatSpriteEngine and KiwiSoundEngine.

This fixes an issue with per-channel volume settings not working
correctly in Haruurare (and presumably other games).
2022-05-04 20:30:03 -07:00
Nunuhara Cabbage 5924225bc2 Implement DrawGraph.BrightDestOnly 2022-05-03 21:08:01 -07:00
Nunuhara Cabbage 7fc60f6607 Implement DrawGraph.ScreenDA_DAxSA 2022-05-03 20:48:21 -07:00
Nunuhara Cabbage 44891458f1 Implement DrawGraph.SaturDP_DPxSA 2022-05-03 20:01:48 -07:00
Nunuhara Cabbage 703a66106f Implement DrawGraph.FillMultiply 2022-05-03 18:57:06 -07:00
Nunuhara Cabbage af33413826 Implement DrawGraph.FillScreen 2022-05-03 18:53:55 -07:00
Nunuhara Cabbage 54f6ece82d Implement DrawGraph.FillAMapGradationUD 2022-05-03 18:49:40 -07:00
Nunuhara Cabbage 3b75b6b545 Implement DrawGraph.BlendScreenAlpha
This completes the full suite of DrawGraph blending functions.
2022-05-02 21:18:49 -07:00
Nunuhara Cabbage e65560b67a Implement DrawGraph.BlendMultiply 2022-05-02 20:48:42 -07:00
Nunuhara Cabbage 2fd081234b Implement DrawGraph.BlendScreen 2022-05-02 20:43:16 -07:00
Nunuhara Cabbage 65be47e05b Implement DrawGraph.BlendUseAMapColor 2022-05-02 20:35:02 -07:00
Nunuhara Cabbage 9108ce19ea Implement DrawGraph.BlendAMapAlphaSrcBright 2022-05-02 18:19:09 -07:00
Nunuhara Cabbage 2f573803c4 Implement DrawGraph.BlendAMapBright 2022-05-02 17:01:23 -07:00
Nunuhara Cabbage 6d745054a4 Implement DrawGraph.BlendAMapSrcOnly 2022-05-02 16:20:40 -07:00
Nunuhara Cabbage 0fc5442e42 Implement DrawGraph.BlendAddSatur 2022-05-02 15:38:53 -07:00
Nunuhara Cabbage d482e165d6 Implement DrawGraph.BlendSrcBright 2022-05-02 15:12:40 -07:00
Nunuhara Cabbage d085951f68 Implement EFFECT_BLUR_FADEOUT
Used in Sengoku Rance (when Ran summons Suzaku).
2022-05-02 11:25:42 -07:00
Nunuhara Cabbage f3969e7d7e Implement EFFECT_ZOOM_IN_CROSSFADE
Used in Sengoku Rance (when Ran summons Suzaku).

The scale curve in this implementation is a bit off compared to
AliceSoft's implementation (theirs looks a bit sharper at the end), but
it's only really noticable with a very long effect time.

AliceSoft's implementation also has a lot more jitter, but I don't think
this is intentional.
2022-05-02 09:41:05 -07:00
Nunuhara Cabbage ae56a0f4b4 fnl: Fix reported width of tab character
The reported size of the tab character seems to be roughly 2.88x the
size of the glyph in the font.

This fixes a text layout issue with the commander info (HP, Job, etc).
2022-05-02 07:54:43 -07:00
Nunuhara Cabbage 6e05874ee1 Implement SACT2.QuakeScreen and EFFECT_OSCILLATE 2022-05-01 13:27:55 -07:00
Nunuhara Cabbage ccf049b4d5 Implement fade effects
Implement EFFECT_FADEOUT, EFFECT_FADEIN, EFFECT_WHITEOUT and
EFFECT_WHITEIN.

I'm not aware of these being used in any game (fade effects seem to be
implemented manually most of the time).
2022-05-01 12:06:53 -07:00
Nunuhara Cabbage 237fbebcf5 Implement EFFECT_ZOOM_LR and EFFECT_ZOOM_RL
Used in Sengoku Rance.

These are implemented using DrawGraph primitives since it's simpler than
writing a shader in this case.
2022-05-01 11:43:24 -07:00
Nunuhara Cabbage 8d381dbf49 Ensure _ModuleInit runs after VM reset
Fixes crash after game over in MangaGamer version of Sengoku Rance.
2022-05-01 08:23:05 -07:00
Nunuhara Cabbage b0d1549964 fnl: implement space_scale_x
Fixes some text layout issues.

Text rendering/layout in the MangaGamer version of Sengoku Rance is now
basically working as intended.
2022-04-30 11:15:06 -07:00
Nunuhara Cabbage a25f066a05 fnl: eliminate text halo
Fill fully-transparent pixels on the destination texture with the text
color before rendering to it. This eliminates halos around text caused
by the invisible texture color (usually black) being blended with the
text.
2022-04-30 10:52:55 -07:00
Nunuhara Cabbage 0d771384da Fix SengokuRanceFont.SP_SetTextMetricsClassic
This function doesn't overwrite values in the text style that aren't
contained in the sact_text_metrics_t object.
2022-04-30 06:33:20 -07:00
Nunuhara Cabbage f2dd4def12 Fix bug in gfx_draw_glyph
blend_amap_color_shader now uses the alpha value.
2022-04-29 18:13:22 -07:00
Nunuhara Cabbage f7b6da9679 Implement DrawGraph.BlendAMapColorAlpha
Used in the Rance VI credits.
2022-04-28 20:43:55 -07:00
Nunuhara Cabbage 9089fa1fd1 Rewrite fnl font renderer
Only unscaled glyph bitmaps are now cached in regular memory. Scaled
glyphs are stored as textures on the GPU. Only the alpha channel on
glyph textures is used, with the color being provided as an input to the
shader.

Outline and bold rendering is improved by using a simple dilate shader.
This looks okay but could be improved (the result is a bit blurry
still).
2022-04-28 19:13:27 -07:00
Nunuhara Cabbage 8fb0153963 SengokuRanceFont: anti-aliasing and glyph caching
This improves the look and (especially) the performance of text
rendering in the MangaGamer version of Sengoku Rance.

There are still some bugs/unimplemented features, but the game should be
more or less bearable to play in this state.
2022-04-24 17:19:27 -07:00
Nunuhara Cabbage 3b72b88e9c SengokuRanceFont improvements
The game now basically runs, but with very bad performance and lots of
aliasing on text.

Need to implement anti-aliasing and caching of rendered glyphs next.
2022-04-23 22:52:07 -07:00
Nunuhara Cabbage 547524d07b SACT2: render sprites in correct order for same Z
If two sprites have the same Z value, they are rendered in increasing
order of their sprite numbers.

This fixes an issue in the MangaGamer version of Sengoku Rance, which
depends on this behavior.
2022-04-21 19:04:20 -07:00
Nunuhara Cabbage 76710475fb Simplify/fix SACT2 sprite code
This code was changed at some point so that sact_get_sprite allocates a
sprite and only returns NULL for a negative sprite index, but some
functions were still assuming that it could return NULL under normal
circumstances and trying to manually allocate sprites.

I've gone through all of the SP_* functions to check which ones allocate
a sprite and which ones don't. If a function doesn't allocate a sprite,
sact_try_get_sprite is called instead of sact_get_sprite.

This fixes a crash on startup in the MangaGamer version of Sengoku
Rance (SengokuRanceFont.SP_ClearState was incorrectly allocating a
sprite).
2022-04-20 20:57:44 -07:00
Nunuhara Cabbage 06d51dc30e Include <limits.h> in system4.c
Per #46
2022-04-19 16:45:33 -07:00
Nunuhara Cabbage e8481d04c0 Note glew dependency in README
Per #46
2022-04-19 16:44:29 -07:00
Nunuhara Cabbage da12d6183e Remove "invalid keycode" warnings
Some games (e.g. Rance VI) just scan through all all keys up to 256 when
waiting for input.
2022-04-18 07:19:32 -07:00
Nunuhara Cabbage 3d5f63a583 Handle special character mapping in Rance VI (EN) 2022-04-17 17:03:38 -07:00
Nunuhara Cabbage 8639e53348 debugger: correctly print bool, lint and NULL 2022-04-17 15:24:00 -07:00
Nunuhara Cabbage 9bcd17a151 Add --font-x-scale option
Add an option to control the horizontal scaling of text. This is mainly
to work around text overflow issues in the MangaGamer version of Rance
02 (an appropriate value is set automatically for that game).
2022-04-17 09:44:44 -07:00
Nunuhara Cabbage 55aed4c755 Implement EFFECT_TURN_PAGE
Used in Rance VI.
2022-04-16 21:51:12 -07:00
Nunuhara Cabbage c1e9099a6c Implement EFFECT_LINEAR_BLUR
Used in Rance VI.
This implementation is not perfect, but it gets pretty close.

Alicesoft's implementation has a sharper curve on the blur size around
t=0.5, giving a "snappy" effect at the middle of the transition.
2022-04-16 10:47:59 -07:00
Nunuhara Cabbage 5b436ed98e Merge pull request #45 from kichikuou/compat-table
Update game_compatibility.md
2022-04-15 18:50:24 -07:00
Nunuhara Cabbage f58c1b43bc audio: fix corner cases in fade implementation
Properly handle the case where the stream loops while fading, by
tracking the elapsed frame count rather than comparing the current frame
with a computed end position.

Properly handle the case where time=0, by applying the volume
immediately instead of in the audio callback.

This fixes some audio bugs in Rance VI.
2022-04-15 11:31:55 -07:00
kichikuou 92ee64dcb8 Update game_compatibility.md
- Change DALK外伝 and ままにょにょ to unsupported
- Expand ALICEの館7 games
2022-04-15 19:45:07 +09:00
Nunuhara Cabbage 0ab9a59e99 Implement SystemService.SetMixerName
Used in Rance VI (at game over screen).
2022-04-14 16:21:24 -07:00
Nunuhara Cabbage 68ca748296 Fix bug in vm_free
This function is not supposed to call destructors, but was calling
heap_unref instead of exit_unref on local pages.

Fixes a bug in Rance VI where the game would crash on game over.
2022-04-14 16:19:26 -07:00
Nunuhara Cabbage 21cb503c06 Read debugger config at startup
Read .xsys4-debugrc from ~/.xsystem4 and/or the game directory on
startup. This is just a text file with one debugger command per line.
Can be used to set breakpoints or log functions automatically at
startup.

This can also be used to work around a limitation on Windows where the
IME doesn't work in the debugger, making it impossible to input Japanese
text.
2022-04-14 10:54:00 -07:00
Nunuhara Cabbage 9ede2d7af9 debugger: add vm-state command
Add vm-state command, which prints disassembly around the current
instruction pointer and the current contents of the stack.

It was necessary to change how breakpoints are implemented for this.
When adding a breakpoint, the original opcode now remains in the
instruction stream, bitwise-or'd with BREAKPOINT. A hash table indexed
by address is used to store breakpoint objects.
2022-04-14 09:08:57 -07:00
Nunuhara Cabbage caf11f3991 Debugger improvements
* Add "frame" command to change the current frame.
* Add "members" command to print struct members for current frame (if it's
  a method frame).
* Support printing member variables (e.g. "this.var") in the "print"
  command.
2022-04-12 19:18:05 -07:00
Nunuhara Cabbage 78354cbdaf audio: seek to 0 when stopping stream
Fix issue in Rance VI where BGM would resume playing from the previous
position instead of restarting after a stream was stopped.

Also fix an issue where a stale sample could be played when starting a
stream after it had been stopped.
2022-04-11 21:25:31 -07:00
Nunuhara Cabbage af3af870fa Add game compatibility table 2022-04-11 18:54:50 -07:00
Nunuhara Cabbage 5e1ab7894f Respect UseJoypad value in System40.ini
Joypad support is enabled if UseJoypad = true. This can be overridden by
the --joypad option, which now takes an optional argument, which may be
"off".
2022-04-11 18:05:51 -07:00
Nunuhara Cabbage 951834fb57 Improve joypad input mapping
Implement buttons 1-4 as left analog stick directions (with cooldown) to
match SACT2.

Other buttons are also remapped to match the SACT2 mapping.
2022-04-11 17:45:21 -07:00
Nunuhara Cabbage 34fa732f91 Use fallback for unimplemented effects
Use EFFECT_BLUR_CROSSFADE as a fallback for unimplemented effects.
2022-04-10 18:50:49 -07:00
Nunuhara Cabbage 3507ebc609 Fix texture leak in sprite_set_cg_2x 2022-04-10 18:43:41 -07:00
Nunuhara Cabbage 5bff9aa922 Fix channel_play/channel_stop return values
The corresponding SACT2 functions return 1 if the channel is already
playing/stopped.

This eliminates some error message spam on the console.
2022-04-10 18:33:32 -07:00
Nunuhara Cabbage 912a73d42a Implement HLLs for English version of Rance VI 2022-04-10 18:24:47 -07:00
Nunuhara Cabbage ef8ebadc7e Fix bug in SACT2.CG_IsExist 2022-04-10 15:32:41 -07:00
Nunuhara Cabbage 5581417937 Implement SACT2.WP_SetSP
Used in English version of Rance VI.
2022-04-10 09:04:00 -07:00
Nunuhara Cabbage 75bb6d1e43 Guard against division by zero in MOD 2022-04-10 09:02:30 -07:00
Nunuhara Cabbage eca92c4f7e Add compatibility hack for English Daibanchou
Gpx2Plus.CopyStretchReduceAMap behaves differently in the English
version.

Fixes an issue with text being squashed horizontally on the regional
phase menus.
2022-04-09 11:42:17 -07:00
Nunuhara Cabbage 322eccb371 Simplify sact_Effect 2022-04-09 09:02:52 -07:00
Nunuhara Cabbage a48704e0e2 Daibanchou: fix BGM/Sound indexing
Fix issue where wrong sounds/music are played in Daibanchou.
2022-04-08 20:07:48 -07:00
Nunuhara Cabbage 95a7719b65 Implement DrawGraph.CopyRotateX,CopyRotateXUseAmap
Used in Tsuma Shibori.
2022-04-08 18:43:51 -07:00
Nunuhara Cabbage ac248c310c Fix -e encoding on Windows 2022-04-07 18:22:01 -07:00
Nunuhara Cabbage 38df5ea1c1 Use display_sjis0/display_utf0 in messages
Ensure correct encoding for error/warning/log messages.
2022-04-06 19:33:33 -07:00
Nunuhara Cabbage b45e8e73dc Fix replaying animation bug in StoatSpriteEngine
Fix a bug where animations would replay after calling
StoatSpriteEngine.MultiSprite_EndAllMove (e.g. the start of battle
animation in Rance 02 replaying after every attack).
2022-04-06 17:55:28 -07:00
Nunuhara Cabbage 48b53881de Fix bug in load_heap 2022-04-06 17:51:39 -07:00
Nunuhara Cabbage 11e4880def Handle all font weights
System 4 has 4 font weights: light, medium, bold and heavy bold.
SDL_ttf has 2 (normal and bold). For now, xsystem4 treats light/medium
as normal and bold/heavy-bold as bold.
2022-04-05 19:33:56 -07:00
Nunuhara Cabbage e88ae62c08 Remove scene_flip function
It was a bug to call this function outside of sact_Update, because it
set scene_is_dirty to false without first rendering the scene. This can
cause the scene to not be rendered in a timely manner.
2022-04-05 19:31:13 -07:00
Nunuhara Cabbage 8a131d416b Add 'screen' draw method to StoatSpriteEngine
This fixes an issue in Rance 02 where Sill's fire arrow attack had a
black background (reported in #44).
2022-04-05 16:55:47 -07:00
Nunuhara Cabbage 2ca1ce14c5 Fix memory leak in SH_S_ASSIGN_CALLSYS19 2022-04-05 16:40:59 -07:00
Nunuhara Cabbage 5fe61c14d9 Rance 02: render '^' as 'é' 2022-04-04 21:26:23 -07:00
Nunuhara Cabbage 1f239c766f Rance 02: render '}' as dash 2022-04-04 20:17:34 -07:00
Nunuhara Cabbage 6c8b674f0e CharSpriteManager: fix truncated descenders
Fix issue where text descenders would be truncated in games using
CharSpriteManager (e.g. Alice 2010).
2022-04-04 11:32:27 -07:00
Nunuhara Cabbage 89d8210c14 Compatibility hack for Rance 02 (MangaGamer)
The MangaGamer version of Rance 02 has a custom proportional font
implementation which makes assumptions about the font in use. This is
worked around by rewriting their '_CalculateWidth' function to use
fixed-width logic.

I also tried using TTF_SizeUTF8 to get the proper character width but I
found this made the text overflow even worse than using a fixed width
(at least with the default gothic font, perhaps other fonts would fare
better).
2022-04-04 11:20:47 -07:00
Nunuhara Cabbage 6118eef06a Implement EFFECT_UP_DOWN_CROSSFADE 2022-04-04 06:52:51 -07:00
Nunuhara Cabbage 888b491b38 Implement EFFECT_CROSSFADE_LR 2022-04-03 22:35:37 -07:00
Nunuhara Cabbage 26c8f399cb Fix bug in iarray_write_string
Fix bug affecting non-ASCII text in iarray_write_string. This fixes a
bug in ADVLogList_Save/ADVLogList_Load which would cause log text to
become garbled after loading a save.
2022-04-03 21:05:12 -07:00
Nunuhara Cabbage c73842ae75 Fix major memory leak in ADVSceneKeeper
The VM can under no circumstance store it's own data on the heap. Doing
so causes said data to leak into saved VM images. This is the worst kind
of memory leak: even restarting the game will not fix it, because the
data is permanently leaked into the save files.

This will break save compatibility in games that use ADVSceneKeeper
(e.g. Alice 2010 games).
2022-04-03 20:38:28 -07:00
Nunuhara Cabbage fbfa5bbb5f Fix memory leak in ADVLogList_Save 2022-04-03 15:12:41 -07:00
Nunuhara Cabbage f01f002a54 Improve performance of vm_save_image
cJSON_AddArrayItem is O(n), which made saving arrays O(n^2). This was
causing extremely poor performance when saving large arrays, such as
those created by MultiSprite_Encode.

A special cJSON_CreateIntArray_cb function is now used instead, which
can create and populate an array in O(n).
2022-04-03 13:42:36 -07:00
Nunuhara Cabbage 5713742a99 Implement MultiSprite_Encode/MultiSprite_Decode 2022-04-03 13:41:34 -07:00
Nunuhara Cabbage 47cb99927d Update libsys4 2022-04-02 08:32:48 -07:00
Nunuhara Cabbage ae0832921f Fix build error when chibi scheme not present 2022-04-02 07:44:27 -07:00
Nunuhara Cabbage 9fbc9ec5b7 Implement simple command-based debugger interface
Add a new debugger interface using a simple command language. This is
less powerful than the scheme interface (which still exists) but more
ergonomic for interactive debugging.

This debugger has no external dependencies (it will however use readline
if available) and is included in builds by default.

A sample interaction might look like:

    xsystem4 --debug /path/to/game
    dbg(cmd)> breakpoint bar
    Set breakpoint at function 'bar' (0x00001234)
    dbg(cmd)> continue
    Hit breakpoint at function 'bar' (0x00001234)
    dbg(cmd)> backtrace
    #0 0x00001234 in bar
    #1 0x00002222 in foo
    #2 0x00004444 in main
    dbg(cmd)> locals
    [0] i: 2
    [1] s: "baz"
    dbg(cmd)> locals 1
    [0] j: 3
    [1] obj: { m_i = 0; m_s = "" }
    dbg(cmd)> quit
2022-04-01 19:38:55 -07:00
Nunuhara Cabbage 0780442e13 Install debugger.scm to XSYS4_DATA_DIR 2022-03-28 17:54:26 -07:00
Nunuhara Cabbage ba0b97e163 Use UTF-8 file functions
Use functions which expect UTF-8 encoded file names (and convert them to
UTF-16 on Windows).

This should fix various issues on Windows when reading/writing files
with Japanese characters in their names.
2022-03-28 16:50:45 -07:00
Nunuhara Cabbage 73eb1d0e34 Merge branch 'master' of github.com:nunuhara/xsystem4 2022-03-27 15:47:09 -07:00
Nunuhara Cabbage 5dfb82afd7 parts: ConstructionProcess (WIP)
A very partial implementation of some ConstructionProcess functionality.
2022-03-27 15:40:18 -07:00
Nunuhara Cabbage 5b2f9d7536 Refactor GoatGUIEngine and add misc. stubs
Refactor GoatGUIEngine into various files under src/parts/.
The external interface to this code is the functions prefixed with PE_
and generally following the naming of the HLL functions which they
implement.

The reason for this is that there are multiple HLL libraries that
implement more or less the same GUI interface (GoatGUIEngine, GUIEngine
and PartsEngine).

Also added here are a number of miscellaneous stubbed-out HLL functions
that are used by Rance 01 (which now runs up to the point where it tries
to create the title menu).
2022-01-30 10:12:20 -08:00
Nunuhara Cabbage 9904754f06 Add interface for loading CGs by name 2022-01-30 10:03:59 -08:00
Nunuhara Cabbage 6f750e4007 More delegate fixes
1. DG_CALL has to clean up the stack before jumping to the return
   address.
2. DG_SET (contrary to its name) is an append operation; it's basically
   a combination of DG_NEW_FROM_METHOD and DG_PLUSA.
3. DG_SET and DG_PLUSA need to check for and ignore duplicates.
4. Delegate pages store *references* to structs; the VM should NOT copy
   the struct page when copying a delegate page.
2022-01-29 09:55:42 -08:00
Nunuhara Cabbage f0fdb714e5 Implement SH_STRUCTREF_GT_IMM 2022-01-24 15:44:43 -08:00
145 changed files with 26368 additions and 4676 deletions
+38 -6
View File
@@ -4,11 +4,11 @@ xsystem4
xsystem4 is an implementation of AliceSoft's System 4 game engine for unix-like
operating systems.
NOTE: This is a work in progress. I am focusing primarily on the Japanese
version of Sengoku Rance (and by extension, the English fan translation)
which is currently more or less playable. Some other games from the same
era may also work, but I have not done any significant testing on them so
breakage is likely.
Compatiblity
------------
See the [game compatibility table](game_compatibility.md) for a list of games
that can be played on xsystem4.
Building
--------
@@ -19,6 +19,8 @@ First install the dependencies (corresponding Debian package in parentheses):
* bison (bison)
* cglm (libcglm-dev) [optional, fetched by meson if not available]
* flex (flex)
* freetype (libfreetype-dev)
* glew (libglew-dev)
* meson (meson)
* libffi (libffi-dev)
* libpng (libpng-dev)
@@ -26,7 +28,6 @@ First install the dependencies (corresponding Debian package in parentheses):
* libturbojpeg (libturbojpeg0-dev)
* libwebp (libwebp-dev)
* SDL2 (libsdl2-dev)
* SDL2_ttf (libsdl2-ttf-dev)
* zlib (zlib1g-dev)
Then fetch the git submodules,
@@ -46,6 +47,32 @@ Finally install it to your system (optional),
ninja -C build install
Installing
----------
If building from source, run:
ninja -C build install
to install xsystem4 on your system.
### Windows
The recommended way to install on Windows is to copy the xsystem4 directory
into the game directory. E.g. if Sengoku Rance is installed at
`C:\Games\AliceSoft\Sengoku Rance`, then your filesystem should look something
like this:
C:\
Games\
AliceSoft\
Sengoku Rance\
System40.ini
xsystem4\
xsystem4.exe
...
...
Running
-------
@@ -58,3 +85,8 @@ Alternatively, run xsystem4 from within the game directory,
cd /path/to/game_directory
xsystem4
### Windows
If you've installed xsystem4 into the game directory as described above, simply
double-click `xsystem4.exe` to run the game.
+75
View File
@@ -0,0 +1,75 @@
Game Compatibility
==================
The table below lists xsystem4's compatibility with various games.
The values in the "status" column have these meanings:
* Supported - known to be working
* Unsupported - known to be broken
* Unknown - insufficient/no testing to determine compatibility
In practice, many of the games with "unknown" status will run fine (perhaps
with some quirks). If you manage to play an "unknown" game to the end without
issues, please let me know or open a pull request to update this table.
| Game | Status | Notes |
| ------------------------------------------------------- | ----------- | ----- |
| DALK外伝 | Unsupported | |
| ままにょにょ | Unsupported | |
| 大番長 -Big Bang Age- | Supported | |
| Daibanchou -Big Bang Age- (EN) | Supported | |
| 魔女の贖罪 | Unknown | |
| Rance VI -ゼス崩壊- | Supported | |
| Rance VI -Collapse of Zeth- (EN) | Supported | |
| ウルトラ魔法少女まなな Vol.1~Vol.5 | Unknown | |
| 鈴宮刑務娼館 | Unknown | From ALICEの館7 |
| しまいま | Unknown | From ALICEの館7 |
| DUNGEONS & DOLLS | Unsupported | From ALICEの館7 |
| こすぷれれもん | Unknown | From ALICEの館7 |
| エルメイフラワー | Unknown | From ALICEの館7 |
| CGは17年ゼミ | Unknown | From ALICEの館7 |
| でーぴーえすVer_N | Unknown | From ALICEの館7 |
| 大番長外伝 | Unknown | From ALICEの館7 |
| ZERO | Unknown | From ALICEの館7 |
| ぷろGRX | Unknown | From ALICEの館7 |
| Girls | Unknown | From ALICEの館7 |
| 神武 -カムナガラ- | Unknown | From ALICEの館7 |
| オニむス | Unknown | From ALICEの館7 |
| 透色 | Unknown | From ALICEの館7 |
| DEBUT | Unknown | From ALICEの館7 |
| ランス6その後 | Unknown | From ALICEの館7 |
| ほいっぷハニー | Unknown | From ALICEの館7 |
| Text Jam Session | Unknown | From ALICEの館7 |
| 没ロゴの哀しみ | Unknown | From ALICEの館7 |
| スタッフコーナー | Unknown | From ALICEの館7 |
| ぱすてるチャイムContinue | Unsupported | |
| GALZOOアイランド | Supported | |
| ぱすちゃC++ | Unknown | |
| よくばりサボテン | Supported | |
| 妻しぼり | Unknown | |
| 戦国ランス | Supported | |
| Sengoku Rance (EN FanTL) | Supported | |
| Sengoku Rance (MangaGamer) | Supported | |
| だぶる先生らいふっ | Unknown | |
| お嬢様をいいなりにするゲーム | Unknown | |
| 超昂閃忍ハルカ | Unknown | |
| 戦国ランス~三匹が斬ったり突いたり燃やしたり | Unknown | |
| Sengoku Rance -Three for the Slash! Thrust! Burn!- (EN) | Unknown | |
| AliveZ | Unknown | |
| エドランゼ ~Come on!水戸姫様~ | Unknown | |
| 闘神都市III | Supported | |
| ばにしゅ!~おっぱいの消えた王国~ | Unknown | |
| 僕だけの保健室 | Unknown | |
| ももいろガーディアン | Unknown | |
| 超昂閃忍ハルカ ハルカVSエスカレイヤー | Unknown | From Alice 2010 |
| 超昂閃忍ハルカ ―疾風!?忍者大作戦― | Unknown | From Alice 2010 |
| 眼鏡のメイと夏休み | Unknown | From Alice 2010 |
| レイチェルの桜貝 | Unknown | From Alice 2010 |
| 砂漠のニッカ | Unknown | From Alice 2010 |
| ばにしゅ!~この手のひらにおっぱいを~ | Unknown | From Alice 2010 |
| はるうられ -校内赤線区域- | Supported | From Alice 2010 |
| わいどにょ | Supported | From Alice 2010 |
| ランス02 -反逆の少女たち- | Supported | From Alice 2010 |
| Rance 02 -The Rebellious Maidens- (Fan TL) | Supported | |
| Rance 02 -The Rebellious Maidens- (MangaGamer) | Supported | |
| All games released after Alice 2010 | Unsupported | |
+5 -4
View File
@@ -36,14 +36,15 @@ enum asset_type {
const char *asset_strtype(enum asset_type type);
void asset_manager_init(void);
bool asset_manager_load_archive(enum asset_type type, const char *archive_name);
bool asset_exists(enum asset_type type, int no);
bool asset_exists_by_name(enum asset_type type, const char *name, int *id_out);
struct archive_data *asset_get(enum asset_type type, int no);
struct archive_data *asset_get_by_name(enum asset_type type, const char *name, int *id_out);
// FIXME: CG code should be refactored to read from buffer only, not archive,
// then caller can just use asset_get and cg_load
struct cg *asset_cg_load(int no);
bool asset_cg_exists(int no);
struct cg *asset_cg_load_by_name(const char *name, int *id_out);
bool asset_cg_get_metrics(int no, struct cg_metrics *metrics);
void asset_cg_index_init(void);
bool asset_cg_get_metrics_by_name(const char *name, struct cg_metrics *metrics);
#endif /* SYSTEM4_ASSET_MANAGER_H */
+2
View File
@@ -79,6 +79,8 @@ int bgm_get_time_length(int id);
//int wav_prepare_from_file(int id, char *filename);
//int bgm_prepare_from_file(int id, char *filename);
int wav_get_group_num_from_data_num(int no);
struct archive_data;
// Takes ownership of dfile.
+2
View File
@@ -210,7 +210,9 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
/* These utilities create an Array of count items.
* The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/
CJSON_PUBLIC(cJSON *) cJSON_CreateArray_cb(int count, cJSON *(*get_item)(int,void*), void *data);
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray_cb(int count, int (*get_number)(int,void*), void *data);
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count);
+50 -1
View File
@@ -19,15 +19,64 @@
#ifdef DEBUGGER_ENABLED
#include <stdbool.h>
#include <stdint.h>
#include "system4/instructions.h"
#include "vm.h"
#include "xsystem4.h"
#define DBG_ERROR(fmt, ...) sys_warning("ERROR: " fmt "\n", ##__VA_ARGS__)
struct ain_variable;
struct breakpoint {
enum opcode restore_op;
void *data;
void (*cb)(struct breakpoint*);
char *message;
int count;
};
struct dbg_cmd {
const char *fullname;
const char *shortname;
const char *arg_description;
const char *description;
unsigned min_args;
unsigned max_args;
void (*run)(unsigned nr_args, char **args);
};
extern bool dbg_enabled;
extern bool dbg_start_in_debugger;
extern unsigned dbg_current_frame;
void dbg_init(void);
void dbg_fini(void);
void dbg_repl(void);
enum opcode dbg_handle_breakpoint(unsigned bp_no);
void dbg_continue(void);
void dbg_quit(void);
void dbg_start(void(*fun)(void*), void *data);
void dbg_cmd_init(void);
void dbg_cmd_repl(void);
void dbg_cmd_add_module(const char *name, unsigned nr_commands, struct dbg_cmd *commands);
void dbg_handle_breakpoint(void);
bool dbg_set_function_breakpoint(const char *_name, void(*cb)(struct breakpoint*), void *data);
bool dbg_set_address_breakpoint(uint32_t address, void(*cb)(struct breakpoint*), void *data);
bool dbg_set_step_over_breakpoint(void);
bool dbg_set_step_into_breakpoint(void);
bool dbg_set_finish_breakpoint(void);
void dbg_print_frame(unsigned no);
void dbg_print_stack_trace(void);
void dbg_print_stack(void);
void dbg_print_vm_state(void);
union vm_value dbg_eval_string(const char *str, struct ain_type *type_out);
struct string *dbg_value_to_string(struct ain_type *type, union vm_value value, int recursive);
#ifdef HAVE_SCHEME
void dbg_scm_init(void);
void dbg_scm_fini(void);
void dbg_scm_repl(void);
#endif /* HAVE_SCHEME */
#endif /* DEBUGGER_ENABLED */
#endif /* SYSTEM4_DEBUGGER_H */
+2 -2
View File
@@ -21,6 +21,7 @@
#include <stddef.h>
#include <stdint.h>
#include "gfx/gl.h"
#include "plugin.h"
struct page;
struct dgn;
@@ -51,6 +52,7 @@ struct camera {
*/
struct dungeon_context {
struct draw_plugin plugin;
enum draw_dungeon_version version;
int surface;
bool loaded;
@@ -68,7 +70,6 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version
void dungeon_context_free(struct dungeon_context *ctx);
bool dungeon_load(struct dungeon_context *ctx, int num);
void dungeon_set_camera(int surface, float x, float y, float z, float angle, float angle_p);
void dungeon_render(struct dungeon_context *ctx);
void dungeon_set_walked(int surface, int x, int y, int z, int flag);
int dungeon_get_walked(int surface, int x, int y, int z);
int dungeon_calc_conquer(int surface);
@@ -76,6 +77,5 @@ bool dungeon_load_walk_data(int surface, int map, struct page **page);
bool dungeon_save_walk_data(int surface, int map, struct page **page);
struct dungeon_context *dungeon_get_context(int surface);
void dungeon_update(void);
#endif /* SYSTEM4_DUNGEON_H */
+1 -1
View File
@@ -61,7 +61,7 @@ enum effect {
EFFECT_VERTICAL_BAR_BLUR_HD = 41,
EFFECT_AMAP_CROSSFADE2 = 42,
EFFECT_ZOOM_LR = 43,
EFFECT_ZOOR_RL = 44,
EFFECT_ZOOM_RL = 44,
EFFECT_CROSSFADE_LR = 45,
EFFECT_CROSSFADE_RL = 46,
EFFECT_PIXEL_EXPLOSION = 47,
+145
View File
@@ -0,0 +1,145 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_FONT_H
#define SYSTEM4_FONT_H
#include "system4.h"
#include "gfx/gfx.h"
struct fnl;
struct hash_table;
// standard font weight values
enum {
FW_NORMAL = 400,
FW_BOLD = 700,
FW_MEDIUM = 1400,
FW_HEAVY = 1700
};
enum font_face {
FONT_GOTHIC = 0,
FONT_MINCHO = 1
};
enum font_weight {
FONT_WEIGHT_NORMAL,
FONT_WEIGHT_BOLD,
FONT_WEIGHT_HEAVY
};
#define NR_FONT_WEIGHTS (FONT_WEIGHT_HEAVY+1)
struct glyph {
Rectangle rect;
float advance;
Texture t[NR_FONT_WEIGHTS];
};
struct font_size {
float size;
int y_offset;
struct font *font;
struct hash_table *glyph_table;
};
enum charmap {
CHARMAP_UNICODE,
CHARMAP_SJIS
};
struct font {
enum charmap charmap;
struct font_size *(*get_size)(struct font *font, float size);
float (*get_actual_size)(struct font *font, float size);
float (*get_actual_size_round_down)(struct font *font, float size);
bool (*get_glyph)(struct font_size *size, struct glyph *dst, uint32_t code, enum font_weight weight);
float (*size_char)(struct font_size *size, uint32_t code);
};
struct text_style {
unsigned face;
float size;
float bold_width; // SengokuRanceFont
unsigned weight; // SACT2, etc.
float edge_left;
float edge_up;
float edge_right;
float edge_down;
SDL_Color color;
SDL_Color edge_color;
float scale_x;
float space_scale_x;
float font_spacing;
// cached, for SengokuRanceFont
struct font_size *font_size;
};
static inline float text_style_edge_width(struct text_style *ts)
{
return max(max(ts->edge_up, ts->edge_down), max(ts->edge_left, ts->edge_right));
}
static inline bool text_style_has_edge(struct text_style *ts)
{
return text_style_edge_width(ts) > 0.01f;
}
static inline void text_style_set_edge_width(struct text_style *ts, float w)
{
ts->edge_left = w;
ts->edge_up = w;
ts->edge_right = w;
ts->edge_down = w;
}
extern bool gfx_text_advance_edges;
void gfx_font_init(void);
void ft_font_init(void);
struct font *ft_font_load(const char *path);
struct font *fnl_font_load(struct fnl *lib, unsigned index);
bool gfx_set_font(enum font_face face, unsigned int size);
bool gfx_set_font_size(unsigned int size);
bool gfx_set_font_face(enum font_face face);
bool gfx_set_font_weight(int weight);
bool gfx_set_font_underline(bool on);
bool gfx_set_font_strikeout(bool on);
bool gfx_set_font_space(int space);
bool gfx_set_font_color(SDL_Color color);
int gfx_get_font_size(void);
enum font_face gfx_get_font_face(void);
int gfx_get_font_weight(void);
bool gfx_get_font_underline(void);
bool gfx_get_font_strikeout(void);
int gfx_get_font_space(void);
SDL_Color gfx_get_font_color(void);
void gfx_set_font_name(const char *name);
int gfx_render_text(Texture *dst, float x, int y, char *msg, struct text_style *ts);
void gfx_draw_text_to_amap(Texture *dst, int x, int y, char *text);
void gfx_draw_text_to_pmap(Texture *dst, int x, int y, char *text);
float gfx_size_char(struct text_style *ts, const char *ch);
float gfx_size_text(struct text_style *ts, const char *text);
float gfx_get_actual_font_size(unsigned face, float size);
float gfx_get_actual_font_size_round_down(unsigned face, float size);
void gfx_print_text_style(struct text_style *style, int indent);
#endif /* SYSTEM4_FONT_H */
+34 -87
View File
@@ -25,6 +25,7 @@
struct cg;
struct text_metrics;
enum cg_type;
enum draw_method {
DRAW_METHOD_NORMAL,
@@ -72,6 +73,7 @@ void gfx_update_screen_scale(void);
void gfx_set_wait_vsync(bool wait);
void gfx_load_shader(struct shader *dst, const char *vertex_shader_path, const char *fragment_shader_path);
GLuint gfx_load_shader_file(const char *path, GLenum type);
// rendering
void gfx_set_clear_color(int r, int g, int b, int a);
@@ -88,12 +90,15 @@ void gfx_init_texture_with_cg(struct texture *t, struct cg *cg);
void gfx_init_texture_rgba(struct texture *t, int w, int h, SDL_Color color);
void gfx_init_texture_rgb(struct texture *t, int w, int h, SDL_Color color);
void gfx_init_texture_with_pixels(struct texture *t, int w, int h, void *pixels);
void gfx_init_texture_amap(struct texture *t, int w, int h, uint8_t *amap, SDL_Color color);
void gfx_init_texture_rmap(struct texture *t, int w, int h, uint8_t *rmap);
void gfx_copy_main_surface(struct texture *dst);
void gfx_delete_texture(struct texture *t);
GLuint gfx_set_framebuffer(GLenum target, Texture *t, int x, int y, int w, int h);
void gfx_reset_framebuffer(GLenum target, GLuint fbo);
SDL_Color gfx_get_pixel(Texture *t, int x, int y);
void *gfx_get_pixels(Texture *t);
int gfx_save_texture(Texture *t, const char *path, enum cg_type);
// drawing
void gfx_draw_init(void);
@@ -108,28 +113,47 @@ void gfx_copy_use_amap_border(struct texture *dst, int dx, int dy, struct textur
void gfx_copy_amap_max(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h);
void gfx_copy_amap_min(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h);
void gfx_blend(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int a);
void gfx_blend_src_bright(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int a, int rate);
void gfx_blend_add_satur(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_blend_amap(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h);
void gfx_blend_amap_src_only(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_blend_amap_color(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h, int r, int g, int b);
void gfx_blend_amap_color_alpha(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int r, int g, int b, int a);
void gfx_blend_amap_alpha(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h, int a);
void gfx_blend_amap_bright(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int rate);
void gfx_blend_amap_alpha_src_bright(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int alpha, int rate);
void gfx_blend_use_amap_color(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int r, int g, int b, int rate);
void gfx_blend_screen(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_blend_multiply(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_blend_screen_alpha(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int a);
void gfx_fill(struct texture *dst, int x, int y, int w, int h, int r, int g, int b);
void gfx_fill_alpha_color(struct texture *dst, int x, int y, int w, int h, int r, int g, int b, int a);
void gfx_fill_amap(struct texture *dst, int x, int y, int w, int h, int a);
void gfx_fill_amap_over_border(Texture *dst, int x, int y, int w, int h, int alpha, int border);
void gfx_fill_amap_under_border(Texture *dst, int x, int y, int w, int h, int alpha, int border);
void gfx_fill_amap_gradation_ud(Texture *dst, int x, int y, int w, int h, int up_a, int down_a);
void gfx_fill_screen(Texture *dst, int x, int y, int w, int h, int r, int g, int b);
void gfx_fill_multiply(Texture *dst, int x, int y, int w, int h, int r, int g, int b);
void gfx_satur_dp_dpxsa(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_screen_da_daxsa(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_add_da_daxsa(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h);
void gfx_blend_da_daxsa(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h);
void gfx_sub_da_daxsa(struct texture *dst, int dx, int dy, struct texture *src, int sx, int sy, int w, int h);
void gfx_bright_dest_only(Texture *dst, int x, int y, int w, int h, int rate);
void gfx_copy_stretch(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh);
void gfx_copy_stretch_amap(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh);
void gfx_copy_stretch_blend(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh, int a);
void gfx_copy_stretch_blend_amap(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh);
void gfx_copy_stretch_blend_amap_alpha(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh, int a);
void gfx_copy_rot_zoom(Texture *dst, Texture *src, int sx, int sy, int w, int h, float rotate, float mag);
void gfx_copy_rot_zoom_amap(Texture *dst, Texture *src, int sx, int sy, int w, int h, float rotate, float mag);
void gfx_copy_rot_zoom_use_amap(Texture *dst, Texture *src, int sx, int sy, int w, int h, float rotate, float mag);
void gfx_copy_reverse_LR(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_copy_reverse_amap_LR(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_fill_amap_over_border(Texture *dst, int x, int y, int w, int h, int alpha, int border);
void gfx_fill_amap_under_border(Texture *dst, int x, int y, int w, int h, int alpha, int border);
void gfx_copy_rotate_y(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag);
void gfx_copy_rotate_y_use_amap(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag);
void gfx_copy_rotate_x(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag);
void gfx_copy_rotate_x_use_amap(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag);
void gfx_copy_width_blur(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int blur);
void gfx_copy_height_blur(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int blur);
void gfx_copy_amap_width_blur(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int blur);
@@ -137,91 +161,14 @@ void gfx_copy_amap_height_blur(Texture *dst, int dx, int dy, Texture *src, int s
void gfx_copy_with_alpha_map(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h);
void gfx_fill_with_alpha(Texture *dst, int x, int y, int w, int h, int r, int g, int b, int a);
void gfx_copy_stretch_with_alpha_map(Texture *dst, int dx, int dy, int dw, int dh, Texture *src, int sx, int sy, int sw, int sh);
void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width);
void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, SDL_Color color, float scale_x);
void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, float scale_x);
enum font_weight {
FW_NORMAL = 400,
FW_BOLD = 700,
FW_NORMAL2 = 1400,
FW_BOLD2 = 1700
};
enum font_face {
FONT_GOTHIC = 0,
FONT_MINCHO = 1
};
extern const char *font_paths[2];
struct text_metrics {
SDL_Color color;
SDL_Color outline_color;
unsigned int size;
enum font_weight weight;
enum font_face face;
int outline_left;
int outline_up;
int outline_right;
int outline_down;
};
struct font_metrics {
int size;
enum font_face face;
int weight;
bool underline;
bool strikeout;
int space;
SDL_Color color;
};
void gfx_font_init(void);
bool gfx_set_font(enum font_face face, unsigned int size);
bool gfx_set_font_size(unsigned int size);
bool gfx_set_font_face(enum font_face face);
bool gfx_set_font_weight(enum font_weight weight);
bool gfx_set_font_underline(bool on);
bool gfx_set_font_strikeout(bool on);
bool gfx_set_font_space(int space);
bool gfx_set_font_color(SDL_Color color);
int gfx_get_font_size(void);
enum font_face gfx_get_font_face(void);
enum font_weight gfx_get_font_weight(void);
bool gfx_get_font_underline(void);
bool gfx_get_font_strikeout(void);
int gfx_get_font_space(void);
SDL_Color gfx_get_font_color(void);
void gfx_set_font_name(const char *name);
int gfx_render_text(Texture *dst, Point pos, char *msg, struct text_metrics *tm, int char_space);
void gfx_draw_text_to_amap(Texture *dst, int x, int y, char *text);
void gfx_draw_text_to_pmap(Texture *dst, int x, int y, char *text);
struct fnl_font_inst {
struct fnl_font_face *font;
float scale;
SDL_Color color;
SDL_Color outline_color;
int outline_size;
};
struct text_style {
unsigned font_type;
float size;
float bold_width;
SDL_Color color;
float edge_width;
SDL_Color edge_color;
float scale_x;
float space_scale_x;
float font_spacing;
struct fnl_font_size *font_size;
};
struct fnl;
struct fnl_font_face;
int fnl_draw_text(struct fnl *fnl, struct text_style *ts, Texture *dst, int x, int y, char *text);
// debug printing
void gfx_print_color(SDL_Color *c);
void gfx_print_rectangle(Rectangle *r);
void gfx_print_point(Point *p);
void gfx_print_texture(struct texture *t, int indent);
#endif /* SYSTEM4_SDL_CORE_H */
+1
View File
@@ -142,6 +142,7 @@ bool key_is_down(enum sact_keycode code);
void key_clear_flag(void);
bool joy_key_is_down(uint8_t code);
void joy_clear_flag(void);
bool joy_get_stick_status(int controller, int type, float *deg, float *pow);
void mouse_get_pos(int *x, int *y);
void mouse_set_pos(int x, int y);
void mouse_get_wheel(int *forward, int *back);
-627
View File
@@ -1,627 +0,0 @@
/* The MIT License
Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
An example:
#include "khash.h"
KHASH_MAP_INIT_INT(32, char)
int main() {
int ret, is_missing;
khiter_t k;
khash_t(32) *h = kh_init(32);
k = kh_put(32, h, 5, &ret);
kh_value(h, k) = 10;
k = kh_get(32, h, 10);
is_missing = (k == kh_end(h));
k = kh_get(32, h, 5);
kh_del(32, h, k);
for (k = kh_begin(h); k != kh_end(h); ++k)
if (kh_exist(h, k)) kh_value(h, k) = 1;
kh_destroy(32, h);
return 0;
}
*/
/*
2013-05-02 (0.2.8):
* Use quadratic probing. When the capacity is power of 2, stepping function
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
hashing on cache performance and is more robust than linear probing.
In theory, double hashing should be more robust than quadratic probing.
However, my implementation is probably not for large hash tables, because
the second hash function is closely tied to the first hash function,
which reduce the effectiveness of double hashing.
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
2011-12-29 (0.2.7):
* Minor code clean up; no actual effect.
2011-09-16 (0.2.6):
* The capacity is a power of 2. This seems to dramatically improve the
speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
- http://code.google.com/p/ulib/
- http://nothings.org/computer/judy/
* Allow to optionally use linear probing which usually has better
performance for random input. Double hashing is still the default as it
is more robust to certain non-random input.
* Added Wang's integer hash function (not used by default). This hash
function is more robust to certain non-random input.
2011-02-14 (0.2.5):
* Allow to declare global functions.
2009-09-26 (0.2.4):
* Improve portability
2008-09-19 (0.2.3):
* Corrected the example
* Improved interfaces
2008-09-11 (0.2.2):
* Improved speed a little in kh_put()
2008-09-10 (0.2.1):
* Added kh_clear()
* Fixed a compiling error
2008-09-02 (0.2.0):
* Changed to token concatenation which increases flexibility.
2008-08-31 (0.1.2):
* Fixed a bug in kh_get(), which has not been tested previously.
2008-08-31 (0.1.1):
* Added destructor
*/
#ifndef __AC_KHASH_H
#define __AC_KHASH_H
/*!
@header
Generic hash table library.
*/
#define AC_VERSION_KHASH_H "0.2.8"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
/* compiler specific configuration */
#if UINT_MAX == 0xffffffffu
typedef unsigned int khint32_t;
#elif ULONG_MAX == 0xffffffffu
typedef unsigned long khint32_t;
#endif
#if ULONG_MAX == ULLONG_MAX
typedef unsigned long khint64_t;
#else
typedef unsigned long long khint64_t;
#endif
#ifndef kh_inline
#ifdef _MSC_VER
#define kh_inline __inline
#else
#define kh_inline inline
#endif
#endif /* kh_inline */
#ifndef klib_unused
#if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3)
#define klib_unused __attribute__ ((__unused__))
#else
#define klib_unused
#endif
#endif /* klib_unused */
typedef khint32_t khint_t;
typedef khint_t khiter_t;
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
#ifndef kroundup32
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#endif
#ifndef kcalloc
#define kcalloc(N,Z) calloc(N,Z)
#endif
#ifndef kmalloc
#define kmalloc(Z) malloc(Z)
#endif
#ifndef krealloc
#define krealloc(P,Z) realloc(P,Z)
#endif
#ifndef kfree
#define kfree(P) free(P)
#endif
static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct kh_##name##_s { \
khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \
khkey_t *keys; \
khval_t *vals; \
} kh_##name##_t;
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t) \
extern kh_##name##_t *kh_init_##name(void); \
extern void kh_destroy_##name(kh_##name##_t *h); \
extern void kh_clear_##name(kh_##name##_t *h); \
extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); \
extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
extern void kh_del_##name(kh_##name##_t *h, khint_t x);
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
SCOPE kh_##name##_t *kh_init_##name(void) { \
return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t)); \
} \
SCOPE void kh_destroy_##name(kh_##name##_t *h) \
{ \
if (h) { \
kfree((void *)h->keys); kfree(h->flags); \
kfree((void *)h->vals); \
kfree(h); \
} \
} \
SCOPE void kh_clear_##name(kh_##name##_t *h) \
{ \
if (h && h->flags) { \
memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
h->size = h->n_occupied = 0; \
} \
} \
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \
if (h->n_buckets) { \
khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \
k = __hash_func(key); i = k & mask; \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + (++step)) & mask; \
if (i == last) return h->n_buckets; \
} \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \
} else return 0; \
} \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \
khint_t j = 1; \
{ \
kroundup32(new_n_buckets); \
if (new_n_buckets < 4) new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (!new_flags) return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (!new_keys) { kfree(new_flags); return -1; } \
h->keys = new_keys; \
if (kh_is_map) { \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
if (!new_vals) { kfree(new_flags); return -1; } \
h->vals = new_vals; \
} \
} /* otherwise shrink */ \
} \
} \
if (j) { /* rehashing is needed */ \
for (j = 0; j != h->n_buckets; ++j) { \
if (__ac_iseither(h->flags, j) == 0) { \
khkey_t key = h->keys[j]; \
khval_t val; \
khint_t new_mask; \
new_mask = new_n_buckets - 1; \
if (kh_is_map) val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t k, i, step = 0; \
k = __hash_func(key); \
i = k & new_mask; \
while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
__ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
} else { /* write the element and jump out of the loop */ \
h->keys[i] = key; \
if (kh_is_map) h->vals[i] = val; \
break; \
} \
} \
} \
} \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \
} \
kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \
h->n_buckets = new_n_buckets; \
h->n_occupied = h->size; \
h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
} \
return 0; \
} \
SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
{ \
khint_t x; \
if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
if (h->n_buckets > (h->size<<1)) { \
if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
*ret = -1; return h->n_buckets; \
} \
} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
*ret = -1; return h->n_buckets; \
} \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \
khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
else { \
last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) site = i; \
i = (i + (++step)) & mask; \
if (i == last) { x = site; break; } \
} \
if (x == h->n_buckets) { \
if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
else x = i; \
} \
} \
} \
if (__ac_isempty(h->flags, x)) { /* not present at all */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; ++h->n_occupied; \
*ret = 1; \
} else if (__ac_isdel(h->flags, x)) { /* deleted */ \
h->keys[x] = key; \
__ac_set_isboth_false(h->flags, x); \
++h->size; \
*ret = 2; \
} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
return x; \
} \
SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x) \
{ \
if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { \
__ac_set_isdel_true(h->flags, x); \
--h->size; \
} \
}
#define KHASH_DECLARE(name, khkey_t, khval_t) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_PROTOTYPES(name, khkey_t, khval_t)
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
__KHASH_TYPE(name, khkey_t, khval_t) \
__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
KHASH_INIT2(name, static kh_inline klib_unused, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
/* --- BEGIN OF HASH FUNCTIONS --- */
/*! @function
@abstract Integer hash function
@param key The integer [khint32_t]
@return The hash value [khint_t]
*/
#define kh_int_hash_func(key) (khint32_t)(key)
/*! @function
@abstract Integer comparison function
*/
#define kh_int_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract 64-bit integer hash function
@param key The integer [khint64_t]
@return The hash value [khint_t]
*/
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
/*! @function
@abstract 64-bit integer comparison function
*/
#define kh_int64_hash_equal(a, b) ((a) == (b))
/*! @function
@abstract const char* hash function
@param s Pointer to a null terminated string
@return The hash value
*/
static kh_inline khint_t __ac_X31_hash_string(const char *s)
{
khint_t h = (khint_t)*s;
if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
return h;
}
/*! @function
@abstract Another interface to const char* hash function
@param key Pointer to a null terminated string [const char*]
@return The hash value [khint_t]
*/
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
/*! @function
@abstract Const char* comparison function
*/
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
static kh_inline khint_t __ac_Wang_hash(khint_t key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
#define kh_int_hash_func2(key) __ac_Wang_hash((khint_t)key)
/* --- END OF HASH FUNCTIONS --- */
/* Other convenient macros... */
/*!
@abstract Type of the hash table.
@param name Name of the hash table [symbol]
*/
#define khash_t(name) kh_##name##_t
/*! @function
@abstract Initiate a hash table.
@param name Name of the hash table [symbol]
@return Pointer to the hash table [khash_t(name)*]
*/
#define kh_init(name) kh_init_##name()
/*! @function
@abstract Destroy a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_destroy(name, h) kh_destroy_##name(h)
/*! @function
@abstract Reset a hash table without deallocating memory.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
*/
#define kh_clear(name, h) kh_clear_##name(h)
/*! @function
@abstract Resize a hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param s New size [khint_t]
*/
#define kh_resize(name, h, s) kh_resize_##name(h, s)
/*! @function
@abstract Insert a key to the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@param r Extra return code: -1 if the operation failed;
0 if the key is present in the hash table;
1 if the bucket is empty (never used); 2 if the element in
the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t]
*/
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
/*! @function
@abstract Retrieve a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys]
@return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
*/
#define kh_get(name, h, k) kh_get_##name(h, k)
/*! @function
@abstract Remove a key from the hash table.
@param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*]
@param k Iterator to the element to be deleted [khint_t]
*/
#define kh_del(name, h, k) kh_del_##name(h, k)
/*! @function
@abstract Test whether a bucket contains data.
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return 1 if containing data; 0 otherwise [int]
*/
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
/*! @function
@abstract Get key given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Key [type of keys]
*/
#define kh_key(h, x) ((h)->keys[x])
/*! @function
@abstract Get value given an iterator
@param h Pointer to the hash table [khash_t(name)*]
@param x Iterator to the bucket [khint_t]
@return Value [type of values]
@discussion For hash sets, calling this results in segfault.
*/
#define kh_val(h, x) ((h)->vals[x])
/*! @function
@abstract Alias of kh_val()
*/
#define kh_value(h, x) ((h)->vals[x])
/*! @function
@abstract Get the start iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The start iterator [khint_t]
*/
#define kh_begin(h) (khint_t)(0)
/*! @function
@abstract Get the end iterator
@param h Pointer to the hash table [khash_t(name)*]
@return The end iterator [khint_t]
*/
#define kh_end(h) ((h)->n_buckets)
/*! @function
@abstract Get the number of elements in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of elements in the hash table [khint_t]
*/
#define kh_size(h) ((h)->size)
/*! @function
@abstract Get the number of buckets in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@return Number of buckets in the hash table [khint_t]
*/
#define kh_n_buckets(h) ((h)->n_buckets)
/*! @function
@abstract Iterate over the entries in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param kvar Variable to which key will be assigned
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach(h, kvar, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(kvar) = kh_key(h,__i); \
(vvar) = kh_val(h,__i); \
code; \
} }
/*! @function
@abstract Iterate over the values in the hash table
@param h Pointer to the hash table [khash_t(name)*]
@param vvar Variable to which value will be assigned
@param code Block of code to execute
*/
#define kh_foreach_value(h, vvar, code) { khint_t __i; \
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
if (!kh_exist(h,__i)) continue; \
(vvar) = kh_val(h,__i); \
code; \
} }
/* More convenient interfaces */
/*! @function
@abstract Instantiate a hash set containing integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT(name) \
KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash map containing integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT(name, khval_t) \
KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
/*! @function
@abstract Instantiate a hash set containing 64-bit integer keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_INT64(name) \
KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
/*! @function
@abstract Instantiate a hash map containing 64-bit integer keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_INT64(name, khval_t) \
KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
typedef const char *kh_cstr_t;
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
*/
#define KHASH_SET_INIT_STR(name) \
KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
/*! @function
@abstract Instantiate a hash map containing const char* keys
@param name Name of the hash table [symbol]
@param khval_t Type of values [type]
*/
#define KHASH_MAP_INIT_STR(name, khval_t) \
KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
#endif /* __AC_KHASH_H */
-94
View File
@@ -1,94 +0,0 @@
/* The MIT License
Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/*
An example:
#include "kvec.h"
int main() {
kvec_t(int) array;
kv_init(array);
kv_push(int, array, 10); // append
kv_a(int, array, 20) = 5; // dynamic
kv_A(array, 20) = 4; // static
kv_destroy(array);
return 0;
}
*/
/*
2008-09-22 (0.1.0):
* The initial version.
*/
#ifndef AC_KVEC_H
#define AC_KVEC_H
#include <stdlib.h>
#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
#define kvec_t(type) struct { size_t n, m; type *a; }
#define kv_decl(name, type) typedef struct { size_t n, m; type *a; } name
#define kv_init(v) ((v).n = (v).m = 0, (v).a = 0)
#define kv_destroy(v) free((v).a)
#define kv_A(v, i) ((v).a[(i)])
#define kv_pop(v) ((v).a[--(v).n])
#define kv_size(v) ((v).n)
#define kv_max(v) ((v).m)
#define kv_data(v) ((v).a)
#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
#define kv_copy(type, v1, v0) do { \
if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n); \
(v1).n = (v0).n; \
memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
} while (0) \
#define kv_push(type, v, x) do { \
if ((v).n == (v).m) { \
(v).m = (v).m? (v).m<<1 : 2; \
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m); \
} \
(v).a[(v).n++] = (x); \
} while (0)
#define kv_pushp(type, v) ((((v).n == (v).m)? \
((v).m = ((v).m? (v).m<<1 : 2), \
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
: 0), \
((v).a + ((v).n++)))
#define kv_a(type, v, i) (((v).m <= (size_t)(i)? \
((v).m = (v).n = (i) + 1, kv_roundup32((v).m), \
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
: (v).n <= (size_t)(i)? (v).n = (i) + 1 \
: 0), \
(v).a[(i)])
#endif
+14 -8
View File
@@ -23,6 +23,11 @@
#include <stdint.h>
// no need to decode on byte-addressable, little-endian arch
#if defined(__i386__) || defined(__x86_64__)
#define LittleEndian_getDW(b, i) (*((int32_t*)((uint8_t*)(b)+(i))))
#define LittleEndian_getW(b, i) (*((int16_t*)((uint8_t*)(b)+(i))))
#else
static inline int32_t LittleEndian_getDW(const uint8_t *b, int i)
{
int c0, c1, c2, c3;
@@ -36,6 +41,15 @@ static inline int32_t LittleEndian_getDW(const uint8_t *b, int i)
return d0 + (d1 << 16);
}
static inline int16_t LittleEndian_getW(const uint8_t *b, int i)
{
int c0, c1;
c0 = *(b + i + 0);
c1 = *(b + i + 1);
return c0 + (c1 << 8);
}
#endif /* defined(__i386__) || defined(__x86_64__) */
static inline int32_t LittleEndian_get3B(const uint8_t *b, int i)
{
int c0, c1, c2;
@@ -45,14 +59,6 @@ static inline int32_t LittleEndian_get3B(const uint8_t *b, int i)
return c0 + (c1 << 8) + (c2 << 16);
}
static inline int16_t LittleEndian_getW(const uint8_t *b, int i)
{
int c0, c1;
c0 = *(b + i + 0);
c1 = *(b + i + 1);
return c0 + (c1 << 8);
}
static inline void LittleEndian_putDW(uint8_t *dst, int i, uint32_t dword)
{
dst[i] = (uint8_t)(dword);
+6
View File
@@ -43,11 +43,17 @@ struct wai *wai_get(int no);
void mixer_init(void);
int mixer_get_numof(void);
const char *mixer_get_name(int n);
int mixer_set_name(int n, const char *name);
int mixer_get_volume(int n, int *volume);
int mixer_set_volume(int n, int volume);
int mixer_get_mute(int n, int *mute);
int mixer_set_mute(int n, int mute);
struct sts_mixer_stream_t;
int mixer_stream_play(struct sts_mixer_stream_t* stream, int volume);
bool mixer_stream_set_volume(int voice, int volume);
void mixer_stream_stop(int voice);
struct archive_data;
struct channel;
enum asset_type;
+31
View File
@@ -0,0 +1,31 @@
/* Copyright (C) 2023 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_MOVIE_H
#define SYSTEM4_MOVIE_H
struct movie_context;
struct sact_sprite;
struct movie_context *movie_load(const char *filename);
void movie_free(struct movie_context *mc);
bool movie_play(struct movie_context *mc);
bool movie_draw(struct movie_context *mc, struct sact_sprite *sprite);
bool movie_is_end(struct movie_context *mc);
int movie_get_position(struct movie_context *mc);
bool movie_set_volume(struct movie_context *mc, int volume /* 0-100 */);
#endif /* SYSTEM4_MOVIE_H */
+188
View File
@@ -0,0 +1,188 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_PARTS_H
#define SYSTEM4_PARTS_H
#include <stdbool.h>
struct page;
struct string;
// parts.c
bool PE_Init(void);
void PE_Update(int passed_time, bool message_window_show);
void PE_UpdateComponent(int passed_time);
void PE_UpdateParts(int passed_time, bool is_skip, bool message_window_show);
void PE_SetDelegateIndex(int parts_no, int delegate_index);
int PE_GetDelegateIndex(int parts_no);
bool PE_SetPartsCG(int parts_no, struct string *cg_name, int sprite_deform, int state);
bool PE_SetPartsCG_by_index(int parts_no, int cg_no, int sprite_deform, int state);
void PE_GetPartsCGName(int parts_no, struct string **cg_name, int state);
bool PE_SetPartsCGSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
int PE_GetPartsCGNumber(int parts_no, int state);
bool PE_SetLoopCG_by_index(int parts_no, int cg_no, int nr_frames, int frame_time, int state);
bool PE_SetLoopCG(int parts_no, struct string *cg_name, int start_no, int nr_frames,
int frame_time, int state);
bool PE_SetLoopCGSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
bool PE_SetHGaugeCG(int parts_no, struct string *cg_name, int state);
bool PE_SetHGaugeCG_by_index(int parts_no, int cg_no, int state);
bool PE_SetHGaugeRate(int parts_no, int numerator, int denominator, int state);
bool PE_SetHGaugeSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
bool PE_SetVGaugeCG(int parts_no, struct string *cg_name, int state);
bool PE_SetVGaugeCG_by_index(int parts_no, int cg_no, int state);
bool PE_SetVGaugeRate(int parts_no, int numerator, int denominator, int state);
bool PE_SetVGaugeSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
bool PE_SetNumeralCG_by_index(int parts_no, int cg_no, int state);
bool PE_SetNumeralLinkedCGNumberWidthWidthList_by_index(int parts_no, int cg_no,
int w0, int w1, int w2, int w3, int w4, int w5, int w6, int w7, int w8,
int w9, int w_minus, int w_comma, int state);
bool PE_SetNumeralLinkedCGNumberWidthWidthList(int parts_no, struct string *cg_name,
int w0, int w1, int w2, int w3, int w4, int w5, int w6, int w7, int w8,
int w9, int w_minus, int w_comma, int state);
bool PE_SetNumeralNumber(int parts_no, int n, int state);
bool PE_SetNumeralShowComma(int parts_no, bool show_comma, int state);
bool PE_SetNumeralSpace(int parts_no, int space, int state);
bool PE_SetNumeralLength(int parts_no, int length, int state);
bool PE_SetNumeralSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
bool PE_SetPartsRectangleDetectionSize(int PartsNumber, int Width, int Height, int State);
bool PE_SetPartsFlash(int PartsNumber, struct string *pIFlashFileName, int State);
bool PE_IsPartsFlashEnd(int PartsNumber, int State);
int PE_GetPartsFlashCurrentFrameNumber(int PartsNumber, int State);
bool PE_BackPartsFlashBeginFrame(int PartsNumber, int State);
bool PE_StepPartsFlashFinalFrame(int PartsNumber, int State);
void PE_ReleaseParts(int parts_no);
void PE_ReleaseAllParts(void);
void PE_ReleaseAllPartsWithoutSystem(void);
void PE_SetPos(int parts_no, int x, int y);
void PE_SetZ(int parts_no, int z);
void PE_SetShow(int parts_no, bool show);
void PE_SetAlpha(int parts_no, int alpha);
void PE_SetPartsDrawFilter(int PartsNumber, int DrawFilter);
void PE_SetAddColor(int parts_no, int r, int g, int b);
void PE_SetMultiplyColor(int parts_no, int r, int g, int b);
int PE_GetPartsX(int parts_no);
int PE_GetPartsY(int parts_no);
int PE_GetPartsZ(int parts_no);
int PE_GetPartsWidth(int parts_no, int state);
int PE_GetPartsUpperLeftPosX(int parts_no, int state);
int PE_GetPartsUpperLeftPosY(int parts_no, int state);
int PE_GetPartsHeight(int parts_no, int state);
bool PE_GetPartsShow(int parts_no);
int PE_GetPartsAlpha(int parts_no);
void PE_SetPartsOriginPosMode(int parts_no, int origin_pos_mode);
int PE_GetPartsOriginPosMode(int parts_no);
void PE_SetParentPartsNumber(int parts_no, int parent_parts_no);
bool PE_SetPartsGroupNumber(int PartsNumber, int GroupNumber);
void PE_SetPartsMessageWindowShowLink(int parts_no, bool message_window_show_link);
bool PE_GetPartsMessageWindowShowLink(int PartsNumber);
void PE_SetPartsMagX(int parts_no, float scale_x);
void PE_SetPartsMagY(int parts_no, float scale_y);
void PE_SetPartsRotateX(int parts_no, float rot_x);
void PE_SetPartsRotateY(int parts_no, float rot_y);
void PE_SetPartsRotateZ(int parts_no, float rot_z);
void PE_SetPartsAlphaClipperPartsNumber(int PartsNumber, int AlphaClipperPartsNumber);
void PE_SetPartsPixelDecide(int PartsNumber, bool PixelDecide);
bool PE_SetThumbnailReductionSize(int ReductionSize);
bool PE_SetThumbnailMode(bool Mode);
bool PE_Save(struct page **buffer);
bool PE_SaveWithoutHideParts(struct page **buffer);
bool PE_Load(struct page **buffer);
// GUIEngine
int PE_GetFreeNumber(void);
bool PE_IsExist(int parts_no);
// construction.c
bool PE_AddCreateToPartsConstructionProcess(int parts_no, int w, int h, int state);
bool PE_AddCreatePixelOnlyToPartsConstructionProcess(int parts_no, int w, int h, int state);
bool PE_AddCreateCGToProcess(int parts_no, struct string *cg_name, int state);
bool PE_AddFillToPartsConstructionProcess(int parts_no, int x, int y, int w, int h,
int r, int g, int b, int state);
bool PE_AddFillAlphaColorToPartsConstructionProcess(int parts_no, int x, int y, int w, int h,
int r, int g, int b, int a, int state);
bool PE_AddFillAMapToPartsConstructionProcess(int parts_no, int x, int y, int w, int h, int a, int state);
bool PE_AddDrawCutCGToPartsConstructionProcess(int parts_no, struct string *cg_name,
int dx, int dy, int dw, int dh, int sx, int sy, int sw, int sh, int interp_type, int state);
bool PE_AddCopyCutCGToPartsConstructionProcess(int parts_no, struct string *cg_name,
int dx, int dy, int dw, int dh, int sx, int sy, int sw, int sh, int interp_type, int state);
bool PE_AddCopyTextToPartsConstructionProcess(int parts_no, int x, int y, struct string *text,
int type, int size, int r, int g, int b, float bold_weight,
int edge_r, int edge_g, int edge_b, float edge_weight,
int char_space, int line_space, int state);
bool PE_AddDrawTextToPartsConstructionProcess(int parts_no, int x, int y, struct string *text,
int type, int size, int r, int g, int b, float bold_weight,
int edge_r, int edge_g, int edge_b, float edge_weight,
int char_space, int line_space, int state);
bool PE_BuildPartsConstructionProcess(int parts_no, int state);
bool PE_SetPartsConstructionSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
// input.c
void PE_UpdateInputState(int passed_time);
void PE_SetClickable(int parts_no, bool clickable);
bool PE_GetPartsClickable(int parts_no);
void PE_SetPartsGroupDecideOnCursor(int GroupNumber, bool DecideOnCursor);
void PE_SetPartsGroupDecideClick(int GroupNumber, bool DecideClick);
void PE_SetOnCursorShowLinkPartsNumber(int parts_no, int link_parts_no);
bool PE_SetPartsOnCursorSoundNumber(int parts_no, int sound_no);
bool PE_SetPartsClickSoundNumber(int parts_no, int sound_no);
bool PE_SetClickMissSoundNumber(int sound_no);
void PE_BeginInput(void);
void PE_EndInput(void);
int PE_GetClickPartsNumber(void);
bool PE_IsCursorIn(int parts_no, int mouse_x, int mouse_y, int state);
// motion.c
void PE_AddMotionPos(int parts_no, int begin_x, int begin_y, int end_x, int end_y, int begin_t, int end_t);
void PE_AddMotionPos_curve(int parts_no, int begin_x, int begin_y, int end_x, int end_y,
int begin_t, int end_t, struct string *curve_name);
void PE_AddMotionAlpha(int parts_no, int begin_a, int end_a, int begin_t, int end_t);
void PE_AddMotionAlpha_curve(int parts_no, int begin_a, int end_a, int begin_t, int end_t,
struct string *curve_name);
void PE_AddMotionCG_by_index(int parts_no, int begin_cg_no, int nr_cg, int begin_t, int end_t);
void PE_AddMotionHGaugeRate(int parts_no, int begin_numerator, int begin_denominator,
int end_numerator, int end_denominator, int begin_t, int end_t);
void PE_AddMotionVGaugeRate(int parts_no, int begin_numerator, int begin_denominator,
int end_numerator, int end_denominator, int begin_t, int end_t);
void PE_AddMotionNumeralNumber(int parts_no, int begin_n, int end_n, int begin_t, int end_t);
void PE_AddMotionMagX(int parts_no, float begin, float end, int begin_t, int end_t);
void PE_AddMotionMagY(int parts_no, float begin, float end, int begin_t, int end_t);
void PE_AddMotionRotateX(int parts_no, float begin, float end, int begin_t, int end_t);
void PE_AddMotionRotateY(int parts_no, float begin, float end, int begin_t, int end_t);
void PE_AddMotionRotateZ(int parts_no, float begin, float end, int begin_t, int end_t);
void PE_AddMotionVibrationSize(int parts_no, int begin_w, int begin_h, int begin_t, int end_t);
void PE_AddMotionSound(int sound_no, int begin_t);
void PE_BeginMotion(void);
void PE_EndMotion(void);
void PE_SetMotionTime(int t);
void PE_UpdateMotionTime(int time, bool skip);
bool PE_IsMotion(void);
int PE_GetMotionEndTime(void);
// text.c
bool PE_SetText(int parts_no, struct string *text, int state);
bool PE_AddPartsText(int parts_no, struct string *text, int state);
bool PE_SetPartsTextSurfaceArea(int parts_no, int x, int y, int w, int h, int state);
bool PE_SetFont(int parts_no, int type, int size, int r, int g, int b, float bold_weight, int edge_r, int edge_g, int edge_b, float edge_weight, int state);
bool PE_SetPartsFontType(int parts_no, int type, int state);
bool PE_SetPartsFontSize(int parts_no, int size, int state);
bool PE_SetPartsFontColor(int parts_no, int r, int g, int b, int state);
bool PE_SetPartsFontBoldWeight(int parts_no, float bold_weight, int state);
bool PE_SetPartsFontEdgeColor(int parts_no, int r, int g, int b, int state);
bool PE_SetPartsFontEdgeWeight(int parts_no, float edge_weight, int state);
bool PE_SetTextCharSpace(int parts_no, int char_space, int state);
bool PE_SetTextLineSpace(int parts_no, int line_space, int state);
#endif /* SYSTEM4_PARTS_H */
+4265
View File
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_PLUGIN_H
#define SYSTEM4_PLUGIN_H
struct sact_sprite;
struct draw_plugin {
const char *name;
void (*update)(struct sact_sprite *);
void (*debug_print)(struct sact_sprite *, int indent);
};
#endif /* SYSTEM4_PLUGIN_H */
+275
View File
@@ -0,0 +1,275 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_REIGN_H
#define SYSTEM4_REIGN_H
#define RE_NR_BACK_CGS 16
#define RE_NR_INSTANCE_TARGETS 2
#include <cglm/types.h>
#include "gfx/gfx.h"
#include "plugin.h"
struct hash_table;
enum RE_instance_type {
RE_ITYPE_UNINITIALIZED = 0,
RE_ITYPE_STATIC = 1,
RE_ITYPE_SKINNED = 2,
RE_ITYPE_BILLBOARD = 3,
RE_ITYPE_DIRECTIONAL_LIGHT = 4,
RE_ITYPE_SPECULAR_LIGHT = 6,
RE_ITYPE_PARTICLE_EFFECT = 8,
};
enum RE_motion_state {
RE_MOTION_STATE_STOP = 0,
RE_MOTION_STATE_NOLOOP = 1,
RE_MOTION_STATE_LOOP = 2,
};
enum RE_fog_type {
RE_FOG_NONE = 0,
RE_FOG_LINEAR = 1,
RE_FOG_LIGHT_SCATTERING = 2,
};
enum RE_draw_type {
RE_DRAW_TYPE_NORMAL = 0,
RE_DRAW_TYPE_ADDITIVE = 1,
RE_DRAW_TYPE_MAX = RE_DRAW_TYPE_ADDITIVE
};
struct RE_options {
int anti_aliasing;
int wait_vsync;
};
extern struct RE_options RE_options;
struct RE_camera {
vec3 pos;
float pitch, roll, yaw; // in degrees
float quake_pitch, quake_yaw;
};
struct RE_back_cg {
struct texture texture;
struct string *name;
int no;
float blend_rate;
float x;
float y;
float mag;
bool show;
};
struct RE_plugin {
struct draw_plugin plugin;
int sprite;
int nr_instances;
struct RE_instance **instances;
struct archive *aar;
struct hash_table *model_cache;
struct hash_table *pae_cache;
struct RE_renderer *renderer;
struct RE_camera camera;
mat4 proj_transform;
struct RE_back_cg back_cg[RE_NR_BACK_CGS];
// Settings.
int render_mode;
int shadow_mode;
vec3 shadow_map_light_dir;
float shadow_bias;
int bump_mode;
int bloom_mode;
int glare_mode;
int fog_mode;
enum RE_fog_type fog_type;
float fog_near;
float fog_far;
vec3 fog_color;
float ls_beta_r;
float ls_beta_m;
float ls_g;
float ls_distance;
vec3 ls_light_dir;
vec3 ls_light_color;
vec3 ls_sun_color;
int specular_mode;
int light_map_mode;
int soft_fog_edge_mode;
int ssao_mode;
int vertex_blend_mode;
int shader_precision_mode;
int texture_filter_mode;
bool use_power2_texture;
int shadow_map_resolution_level;
int texture_resolution_level;
vec3 global_ambient;
float post_effect_filter_y;
float post_effect_filter_cb;
float post_effect_filter_cr;
};
struct RE_instance {
struct RE_plugin *plugin;
struct model *model;
struct particle_effect *effect;
struct motion *motion;
struct motion *next_motion;
struct height_detector *height_detector;
enum RE_instance_type type;
int target[RE_NR_INSTANCE_TARGETS];
vec3 pos;
float pitch, roll, yaw; // in degrees
vec3 scale;
float alpha;
bool draw;
bool draw_shadow;
bool make_shadow;
float shadow_volume_bone_radius;
bool draw_bump;
float fps;
bool motion_blend;
float motion_blend_rate;
vec3 ambient;
vec3 column_pos;
float column_height;
float column_radius;
float column_angle; // around the Y axis, in degrees
// Billboards
enum RE_draw_type draw_type;
// Lights
vec3 vec;
vec3 diffuse;
vec3 globe_diffuse;
// Private
bool local_transform_needs_update;
mat4 local_transform;
mat3 normal_transform;
mat4 *bone_transforms; // model->nr_bones elements
vec4 bounding_sphere;
struct RE_instance *shadow_volume_instance;
float z_from_camera;
};
struct RE_plugin *RE_plugin_new(void);
void RE_plugin_free(struct RE_plugin *plugin);
bool RE_plugin_bind(struct RE_plugin *plugin, int sprite);
bool RE_plugin_unbind(struct RE_plugin *plugin);
bool RE_build_model(struct RE_plugin *plugin, int elapsed_ms);
bool RE_set_projection(struct RE_plugin *plugin, float width, float height, float near, float far, float deg);
int RE_create_instance(struct RE_plugin *plugin);
bool RE_release_instance(struct RE_plugin *plugin, int instance);
bool RE_instance_set_type(struct RE_instance *instance, int type);
bool RE_instance_load(struct RE_instance *instance, const char *name);
bool RE_instance_load_motion(struct RE_instance *instance, const char *name);
bool RE_instance_load_next_motion(struct RE_instance *instance, const char *name);
bool RE_instance_free_next_motion(struct RE_instance *instance);
bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x, float y, float z);
int RE_instance_get_bone_index(struct RE_instance *instance, const char *name);
bool RE_instance_trans_local_pos_to_world_pos_by_bone(struct RE_instance *instance, int bone, vec3 offset, vec3 out);
float RE_instance_calc_height(struct RE_instance *instance, float x, float z);
bool RE_instance_set_debug_draw_shadow_volume(struct RE_instance *instance, bool draw);
int RE_motion_get_state(struct motion *motion);
bool RE_motion_set_state(struct motion *motion, int state);
float RE_motion_get_frame(struct motion *motion);
bool RE_motion_set_frame(struct motion *motion, float frame);
bool RE_motion_set_frame_range(struct motion *motion, float begin, float end);
bool RE_motion_set_loop_frame_range(struct motion *motion, float begin, float end);
int RE_effect_get_num_object(struct particle_effect *effect);
bool RE_effect_get_camera_quake_flag(struct particle_effect *effect);
bool RE_effect_set_camera_quake_flag(struct particle_effect *effect, bool enable);
struct particle_object *RE_get_effect_object(struct particle_effect *effect, unsigned object);
int RE_particle_get_type(struct particle_object *po);
int RE_particle_get_move_type(struct particle_object *po);
int RE_particle_get_up_vec_type(struct particle_object *po);
float RE_particle_get_move_curve(struct particle_object *po);
void RE_particle_get_frame(struct particle_object *po, int *begin_frame, int *end_frame);
int RE_particle_get_stop_frame(struct particle_object *po);
const char *RE_particle_get_name(struct particle_object *po);
int RE_particle_get_num_pos(struct particle_object *po);
int RE_particle_get_num_pos_unit(struct particle_object *po, int pos);
int RE_particle_get_pos_unit_type(struct particle_object *po, int pos, int unit);
int RE_particle_get_pos_unit_index(struct particle_object *po, int pos, int unit);
int RE_particle_get_num_texture(struct particle_object *po);
const char *RE_particle_get_texture(struct particle_object *po, int texture);
bool RE_particle_get_size(struct particle_object *po, float *begin_size, float *end_size);
bool RE_particle_get_size2(struct particle_object *po, int frame, float *size);
bool RE_particle_get_size_x(struct particle_object *po, int frame, float *size);
bool RE_particle_get_size_y(struct particle_object *po, int frame, float *size);
bool RE_particle_get_size_type(struct particle_object *po, int frame, int *type);
bool RE_particle_get_size_x_type(struct particle_object *po, int frame, int *type);
bool RE_particle_get_size_y_type(struct particle_object *po, int frame, int *type);
int RE_particle_get_num_size2(struct particle_object *po);
int RE_particle_get_num_size_x(struct particle_object *po);
int RE_particle_get_num_size_y(struct particle_object *po);
int RE_particle_get_num_size_type(struct particle_object *po);
int RE_particle_get_num_size_x_type(struct particle_object *po);
int RE_particle_get_num_size_y_type(struct particle_object *po);
int RE_particle_get_blend_type(struct particle_object *po);
const char *RE_particle_get_polygon_name(struct particle_object *po);
int RE_particle_get_num_particles(struct particle_object *po);
int RE_particle_get_alpha_fadein_time(struct particle_object *po);
int RE_particle_get_alpha_fadeout_time(struct particle_object *po);
int RE_particle_get_texture_anime_time(struct particle_object *po);
float RE_particle_get_alpha_fadein_frame(struct particle_object *po);
float RE_particle_get_alpha_fadeout_frame(struct particle_object *po);
float RE_particle_get_texture_anime_frame(struct particle_object *po);
int RE_particle_get_frame_ref_type(struct particle_object *po);
int RE_particle_get_frame_ref_param(struct particle_object *po);
void RE_particle_get_x_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle);
void RE_particle_get_y_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle);
void RE_particle_get_z_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle);
void RE_particle_get_x_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle);
void RE_particle_get_x_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance);
void RE_particle_get_y_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle);
void RE_particle_get_y_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance);
void RE_particle_get_z_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle);
void RE_particle_get_z_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance);
bool RE_particle_get_curve_length(struct particle_object *po, vec3 out);
int RE_particle_get_child_frame(struct particle_object *po);
float RE_particle_get_child_length(struct particle_object *po);
float RE_particle_get_child_begin_slope(struct particle_object *po);
float RE_particle_get_child_end_slope(struct particle_object *po);
float RE_particle_get_child_create_begin_frame(struct particle_object *po);
float RE_particle_get_child_create_end_frame(struct particle_object *po);
int RE_particle_get_child_move_dir_type(struct particle_object *po);
int RE_particle_get_dir_type(struct particle_object *po);
int RE_particle_get_num_damage(struct particle_object *po);
int RE_particle_get_damage(struct particle_object *po, int frame);
float RE_particle_get_offset_x(struct particle_object *po);
float RE_particle_get_offset_y(struct particle_object *po);
bool RE_effect_get_frame_range(struct RE_instance *instance, int *begin_frame, int *end_frame);
bool RE_back_cg_set(struct RE_back_cg *bcg, int no);
bool RE_back_cg_set_name(struct RE_back_cg *bcg, struct string *name, struct archive *aar);
void RE_render(struct sact_sprite *sp);
void RE_debug_print(struct sact_sprite *sp, int indent);
#endif /* SYSTEM4_REIGN_H */
+3 -2
View File
@@ -37,6 +37,7 @@ int sact_SP_Count(void);
int sact_SP_Enum(struct page **array);
int sact_SP_GetMaxZ(void);
int sact_SP_SetCG(int sp, int cg);
int sact_SP_SetCG2X(int sp_no, int cg_no);
int sact_SP_SetCGFromFile(int sp, struct string *filename);
int sact_SP_SaveCG(int sp, struct string *filename);
int sact_SP_Create(int sp, int width, int height, int r, int g, int b, int a);
@@ -64,7 +65,7 @@ int sact_SP_SetTextHome(int sp_no, int x, int y);
int sact_SP_SetTextLineSpace(int sp_no, int px);
int sact_SP_SetTextCharSpace(int sp_no, int px);
int sact_SP_SetTextPos(int sp_no, int x, int y);
int _sact_SP_TextDraw(int sp_no, struct string *text, struct text_metrics *tm);
int _sact_SP_TextDraw(int sp_no, struct string *text, struct text_style *tm);
int sact_SP_TextDraw(int sp_no, struct string *text, struct page *tm);
int sact_SP_TextClear(int sp_no);
int sact_SP_TextHome(int sp_no, int size);
@@ -100,7 +101,7 @@ int sact_TRANS_Begin(int type);
int sact_TRANS_Update(float rate);
int sact_TRANS_End(void);
extern struct text_metrics text_sprite_tm;
extern struct text_style text_sprite_ts;
bool StoatSpriteEngine_SP_SetTextSprite(int sp_no, struct string *text);
void StoatSpriteEngine_SP_SetTextSpriteType(int type);
void StoatSpriteEngine_SP_SetTextSpriteSize(int size);
+7 -1
View File
@@ -20,6 +20,8 @@
#include <stdbool.h>
#include "queue.h"
struct texture;
struct sprite {
TAILQ_ENTRY(sprite) entry;
// The Z-layer of the sprite within the scene
@@ -37,6 +39,8 @@ struct sprite {
bool in_scene;
// The rendering function.
void (*render)(struct sprite*);
// Debug printing function
void (*debug_print)(struct sprite*);
};
extern bool scene_is_dirty;
@@ -44,12 +48,14 @@ extern bool scene_is_dirty;
void scene_register_sprite(struct sprite *sp);
void scene_unregister_sprite(struct sprite *sp);
void scene_render(void);
void scene_flip(void);
int scene_set_wp(int cg_no);
int scene_set_wp_color(int r, int g, int b);
int scene_set_wp_texture(struct texture *tex);
void scene_set_sprite_z(struct sprite *sp, int z);
void scene_set_sprite_z2(struct sprite *sp, int z, int z2);
void scene_print(void);
static inline void scene_sprite_dirty(struct sprite *sp)
{
if (!sp)
+12 -2
View File
@@ -26,10 +26,11 @@
struct string;
struct page;
union vm_value;
struct text_style;
struct sact_sprite {
struct sprite sp;
TAILQ_ENTRY(sact_sprite) entry;
LIST_ENTRY(sact_sprite) entry;
// The sprite's texture (CG or solid color). Initialized lazily.
struct texture texture;
// If no CG is attached to the sprite, the solid color to fill with.
@@ -50,6 +51,8 @@ struct sact_sprite {
int no;
// The CG number attached to the sprite.
int cg_no;
// (optional) Draw plugin bound to this sprite.
struct draw_plugin *plugin;
};
static inline void sprite_dirty(struct sact_sprite *sp)
@@ -60,7 +63,10 @@ static inline void sprite_dirty(struct sact_sprite *sp)
void sprite_free(struct sact_sprite *sp);
struct texture *sprite_get_texture(struct sact_sprite *sp);
void sprite_set_cg(struct sact_sprite *sp, struct cg *cg);
void sprite_set_cg_2x(struct sact_sprite *sp, struct cg *cg);
int sprite_set_cg_from_asset(struct sact_sprite *sp, int cg_no);
int sprite_set_cg_2x_from_asset(struct sact_sprite *sp, int cg_no);
int sprite_set_cg_by_name(struct sact_sprite *sp, const char *name);
int sprite_set_cg_from_file(struct sact_sprite *sp, const char *path);
int sprite_save_cg(struct sact_sprite *sp, const char *path);
void sprite_init(struct sact_sprite *sp, int w, int h, int r, int g, int b, int a);
@@ -86,7 +92,7 @@ void sprite_set_text_home(struct sact_sprite *sp, int x, int y);
void sprite_set_text_line_space(struct sact_sprite *sp, int px);
void sprite_set_text_char_space(struct sact_sprite *sp, int px);
void sprite_set_text_pos(struct sact_sprite *sp, int x, int y);
void sprite_text_draw(struct sact_sprite *sp, struct string *text, struct text_metrics *tm);
void sprite_text_draw(struct sact_sprite *sp, struct string *text, struct text_style *ts);
void sprite_text_clear(struct sact_sprite *sp);
void sprite_text_home(struct sact_sprite *sp, int size);
void sprite_text_new_line(struct sact_sprite *sp, int size);
@@ -101,5 +107,9 @@ bool sprite_is_point_in(struct sact_sprite *sp, int x, int y);
bool sprite_is_point_in_rect(struct sact_sprite *sp, int x, int y);
int sprite_get_amap_value(struct sact_sprite *sp, int x, int y);
void sprite_get_pixel_value(struct sact_sprite *sp, int x, int y, int *r, int *g, int *b);
void sprite_bind_plugin(struct sact_sprite *sp, struct draw_plugin *plugin);
void sprite_call_plugins(void);
void sprite_print(struct sact_sprite *sp);
#endif /* SYSTEM4_SPRITE_H */
+9 -9
View File
@@ -39,6 +39,11 @@ enum {
STS_MIXER_SAMPLE_FORMAT_FLOAT // floats
};
enum {
STS_STREAM_COMPLETE = 0,
STS_STREAM_CONTINUE = 1
};
////////////////////////////////////////////////////////////////////////////////
//
@@ -66,7 +71,7 @@ typedef struct {
// The callback which will be called when the stream needs more data.
typedef int (*sts_mixer_stream_callback)(sts_mixer_sample_t* sample, void* userdata);
typedef struct {
typedef struct sts_mixer_stream_t {
void* userdata; // a userdata pointer which will passed to the callback
sts_mixer_stream_callback callback; // this callback will be called when the stream needs more data
sts_mixer_sample_t sample; // the current stream "sample" which holds the current piece of audio
@@ -160,11 +165,6 @@ enum {
STS_MIXER_VOICE_STREAMING
};
enum {
STS_STREAM_COMPLETE = 0,
STS_STREAM_CONTINUE = 1
};
static float sts_mixer__clamp(const float value, const float min, const float max) {
if (value < min) return min;
else if (value > max) return max;
@@ -329,14 +329,14 @@ void sts_mixer_mix_audio(sts_mixer_t* mixer, void* output, unsigned int samples)
voice->position = 0.0f;
position = 0;
}
left += sts_mixer__clamp_sample(sts_mixer__get_sample(&voice->stream->sample, position) * voice->gain);
right += sts_mixer__clamp_sample(sts_mixer__get_sample(&voice->stream->sample, position + 1) * voice->gain);
// added in xsystem4: allow stopping stream via callback return value
if (status == STS_STREAM_COMPLETE) {
sts_mixer_stop_voice(mixer, i);
} else {
left += sts_mixer__clamp_sample(sts_mixer__get_sample(&voice->stream->sample, position) * voice->gain);
right += sts_mixer__clamp_sample(sts_mixer__get_sample(&voice->stream->sample, position + 1) * voice->gain);
voice->position += (float)voice->stream->sample.frequency * advance;
}
}
}
}
+28 -3
View File
@@ -88,10 +88,16 @@ static inline void stack_push_value(union vm_value v)
#define stack_set(n, v) (stack_set_value((n), vm_value_cast(v)))
#define stack_push(v) (stack_push_value(vm_value_cast(v)))
union vm_value stack_pop(void);
union vm_value stack_peek(int n);
union vm_value *stack_peek_var(void);
union vm_value local_get(int varno);
union vm_value global_get(int varno);
union vm_value member_get(int varno);
void global_set(int varno, union vm_value val, bool call_dtors);
struct page *local_page(void);
struct page *get_local_page(int frame_no);
struct page *get_struct_page(int frame_no);
int vm_string_ref(struct string *s);
int vm_copy_page(struct page *page);
@@ -102,19 +108,21 @@ void vm_call(int fno, int struct_page);
int vm_time(void);
void hll_call(int libno, int fno);
void link_libraries(void);
bool library_exists(int libno);
bool library_function_exists(int libno, int fno);
void init_libraries(void);
void exit_libraries(void);
void vm_stack_trace(void);
noreturn void _vm_error(const char *fmt, ...);
noreturn void vm_exit(int code);
_Noreturn void _vm_error(const char *fmt, ...);
_Noreturn void vm_exit(int code);
#define VM_ERROR(fmt, ...) \
_vm_error("*ERROR*(%s:%s:%d): " fmt "\n", __FILE__, __func__, __LINE__, ##__VA_ARGS__)
#ifdef VM_PRIVATE
#include "little_endian.h"
#include "system4/ain.h"
struct function_call {
int32_t fno;
@@ -129,6 +137,23 @@ extern int32_t call_stack_ptr;
extern size_t instr_ptr;
// Read argument N for the current instruction.
static inline int32_t get_argument(int n)
{
return LittleEndian_getDW(ain->code, instr_ptr + 2 + n*4);
}
// XXX: not strictly portable
static inline float get_argument_float(int n)
{
union vm_value v;
v.i = LittleEndian_getDW(ain->code, instr_ptr + 2 + n*4);
return v.f;
}
uint32_t get_switch_address(int no, int val);
uint32_t get_strswitch_address(int no, struct string *str);
int vm_save_image(const char *key, const char *path);
void vm_load_image(const char *key, const char *path);
struct page *vm_load_image_comments(const char *key, const char *path, int *success);
+6 -1
View File
@@ -40,7 +40,10 @@ struct vm_pointer {
};
#ifdef DEBUG_HEAP
size_t alloc_addr;
size_t ref_addr;
size_t ref_addr[16];
size_t ref_nr;
size_t deref_addr[16];
size_t deref_nr;
size_t free_addr;
#endif
};
@@ -70,6 +73,8 @@ void heap_struct_assign(int lval, int rval);
int32_t heap_alloc_page(struct page *page);
int32_t heap_alloc_string(struct string *s);
void heap_describe_slot(int slot);
/*
* Guarantee `headroom` free slots are available on the heap.
*
+3
View File
@@ -133,6 +133,9 @@ void array_reverse(struct page *page);
// delegates
struct page *delegate_new_from_method(int obj, int fun);
int delegate_numof(struct page *page);
bool delegate_contains(struct page *dst, int obj, int fun);
void delegate_erase(struct page *page, int obj, int fun);
struct page *delegate_append(struct page *dst, int obj, int fun);
struct page *delegate_plusa(struct page *dst, struct page *add);
struct page *delegate_minusa(struct page *dst, struct page *minus);
struct page *delegate_clear(struct page *page);
+24
View File
@@ -36,13 +36,28 @@ struct config {
char *bgi_path;
char *wai_path;
char *ex_path;
char *fnl_path;
char *font_paths[2];
bool joypad;
bool echo;
float text_x_scale;
bool manual_text_x_scale;
};
extern struct config config;
// Convenience functions to avoid cumbersome memory management when passing
// text to printf-like functions
const char *display_sjis0(const char *sjis);
const char *display_sjis1(const char *sjis);
const char *display_sjis2(const char *sjis);
const char *display_utf0(const char *utf);
const char *display_utf1(const char *utf);
const char *display_utf2(const char *utf);
void indent_printf(int indent, const char *fmt, ...);
char *unix_path(const char *path);
char *gamedir_path(const char *path);
char *savedir_path(const char *path);
@@ -54,4 +69,13 @@ void get_time(int *hour, int *min, int *sec, int *ms);
#define XSYS4_DATA_DIR "/usr/local/share/xsystem4"
#endif
#define MMAP_IF_64BIT (sizeof(void*) >= 8 ? ARCHIVE_MMAP : 0)
extern bool game_daibanchou_en;
extern bool game_rance02_mg;
extern bool game_rance6_mg;
extern bool game_rance7_mg;
extern bool id_indexed_afa;
#endif /* XSYSTEM4_H */
+9 -7
View File
@@ -1,12 +1,12 @@
project('system4', 'c',
default_options : ['c_std=c11'])
add_project_arguments('-D_DEFAULT_SOURCE', language : 'c')
add_project_arguments('-DXSYS4_DATA_DIR="' + get_option('prefix') / 'share' / 'xsystem4"', language : 'c')
add_project_arguments('-DXSYS4_DATA_DIR="' + get_option('prefix') / get_option('datadir') / 'xsystem4"', language : 'c')
zlib = dependency('zlib')
libm = meson.get_compiler('c').find_library('m', required: false)
sdl2 = dependency('sdl2')
sdl2ttf = dependency('SDL2_ttf')
ft2 = dependency('freetype2')
ffi = dependency('libffi')
tj = dependency('libturbojpeg')
webp = dependency('libwebp')
@@ -14,8 +14,8 @@ png = dependency('libpng')
cglm = dependency('cglm', fallback : ['cglm', 'cglm_dep'])
sndfile = dependency('sndfile')
if get_option('use_gles')
gles = dependency('glesv2')
gles = dependency('glesv2', version : '>=3', required: get_option('opengles'))
if gles.found()
gl_deps = [gles]
add_project_arguments('-DUSE_GLES', language : 'c')
else
@@ -24,7 +24,8 @@ else
gl_deps = [gl, glew]
endif
chibi = dependency('chibi-scheme', required : get_option('debugger'))
chibi = dependency('chibi-scheme', required : false)
readline = dependency('readline', required : false)
flex = find_program('flex')
bison = find_program('bison')
@@ -36,5 +37,6 @@ libsys4_dep = libsys4_proj.get_variable('libsys4_dep')
subdir('src')
install_subdir('shaders', install_dir : 'share' / 'xsystem4')
install_subdir('fonts', install_dir : 'share' / 'xsystem4')
install_subdir('shaders', install_dir : get_option('datadir') / 'xsystem4')
install_subdir('fonts', install_dir : get_option('datadir') / 'xsystem4')
install_data('debugger.scm', install_dir : get_option('datadir') / 'xsystem4')
+1 -1
View File
@@ -1,2 +1,2 @@
option('debugger', type : 'feature', value : 'auto')
option('use_gles', type : 'boolean', value : false, description : 'Target OpenGL ES 3.0')
option('opengles', type : 'feature', value : 'auto', description : 'Target OpenGL ES 3.0')
+26
View File
@@ -0,0 +1,26 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
float alpha = texture(tex, tex_coord).a;
float on = step(0.001, alpha);
frag_color = vec4(on, on, on, alpha);
}
+25
View File
@@ -0,0 +1,25 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex;
uniform vec4 color;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
frag_color = texture(tex, tex_coord) * color;
}
+1 -1
View File
@@ -22,5 +22,5 @@ out vec4 frag_color;
void main() {
vec4 texel = texture(tex, tex_coord);
frag_color = vec4(color.rgb, texel.a);
frag_color = vec4(color.rgb, texel.a * color.a);
}
@@ -15,13 +15,12 @@
*/
uniform sampler2D tex;
uniform float threshold;
uniform vec4 color;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
vec4 texel = texture(tex, tex_coord);
texel.a *= threshold;
frag_color = texel;
frag_color = vec4(color.rgb, texel.r * color.a);
}
+31
View File
@@ -0,0 +1,31 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex;
uniform float threshold;
uniform vec4 color;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
// alpha values at or above `rate + 16` get an alpha of 0
// alpha values below `rate` get an alpha of 255
// alpha values between `rate` and `rate + 16` are blended
float delta = texture(tex, tex_coord).a - threshold;
float alpha = 1.0 - clamp(delta * 16.0, 0.0, 1.0);
frag_color = vec4(color.rgb, alpha);
}
+47
View File
@@ -0,0 +1,47 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex;
uniform float threshold;
uniform vec4 color;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
// the fractional part of threshold becomes a weight value for the
// edge pixels
int size = int(floor(threshold));
int cutoff = size + 1;
float edge_weight = fract(threshold);
vec2 tex_size = vec2(textureSize(tex, 0).xy);
float a_out = 0.0;
for (int x = -cutoff; x <= cutoff; x++) {
for (int y = -cutoff; y <= cutoff; y++) {
float d = distance(vec2(x, y), vec2(0, 0));
if (d > threshold)
continue;
float a = texture(tex, tex_coord + vec2(x, y) / tex_size).r;
if (d > float(size))
a *= edge_weight;
a_out += a;
}
}
frag_color = vec4(color.rgb, min(a_out, 1.0));
}
+72
View File
@@ -0,0 +1,72 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex; // the new scene
uniform sampler2D old; // the old scene
uniform vec2 resolution; // the screen resolution
uniform float progress; // effect progress (0..1)
in vec2 tex_coord;
out vec4 frag_color;
const float PI = 3.14159265;
const vec2 tex_offset = vec2(1.0, 1.0);
const float sigma = 50.0;
vec3 get_pixel(vec2 xy) {
return texture(old, xy).rgb;
}
// incremental gaussian blur algorithm
void main() {
vec2 p = tex_coord * resolution;
float blur_size = progress * 100.0;
float blur_half = blur_size / 2.0;
vec3 gauss;
gauss.x = 1.0 / (sqrt(2.0 * PI) * sigma);
gauss.y = exp(-0.5 / (sigma * sigma));
gauss.z = gauss.y * gauss.y;
vec3 avg = vec3(0.0);
float coefficient_sum = 0.0;
avg += get_pixel(p / resolution) * gauss.x;
coefficient_sum += gauss.x;
gauss.xy *= gauss.yz;
vec2 tex_offset = vec2(0.25, 0.75);
for (float i = 1.0; i <= blur_half; i += 1.0) {
avg += get_pixel((p - i * tex_offset) / resolution) * gauss.x;
avg += get_pixel((p + i * tex_offset) / resolution) * gauss.x;
coefficient_sum += 2.0 * gauss.x;
gauss.xy *= gauss.yz;
}
tex_offset = vec2(0.75, 0.25);
for (float i = 1.0; i <= blur_half; i += 1.0) {
avg += get_pixel((p - i * tex_offset) / resolution) * gauss.x;
avg += get_pixel((p + i * tex_offset) / resolution) * gauss.x;
coefficient_sum += 2.0 * gauss.x;
gauss.xy *= gauss.yz;
}
vec3 old_px = avg / coefficient_sum;
vec3 new_px = texture(tex, tex_coord).rgb;
frag_color = vec4(mix(old_px, new_px, pow(progress, 3.0)), 1.0);
}
+36
View File
@@ -0,0 +1,36 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex; // the new scene
uniform sampler2D old; // the old scene
uniform vec2 resolution; // the screen resolution
uniform float progress; // effect progress (0..1)
in vec2 tex_coord;
out vec4 frag_color;
#define EFFECT_WIDTH 210.0
void main() {
// start position of effect
float lhs = ((resolution.x + EFFECT_WIDTH) * progress) - EFFECT_WIDTH;
// current pixel x-coordinate
float p = tex_coord.x * resolution.x;
// calculate alpha value
float alpha = clamp((p - lhs) / EFFECT_WIDTH, 0.0, 1.0);
vec3 col = mix(texture(tex, tex_coord).rgb, texture(old, tex_coord).rgb, alpha);
frag_color = vec4(col, 1.0);
}
+36
View File
@@ -0,0 +1,36 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex; // the new scene
uniform sampler2D old; // the old scene
uniform vec2 resolution; // the screen resolution
uniform float progress; // effect progress (0..1)
in vec2 tex_coord;
out vec4 frag_color;
#define EFFECT_HEIGHT 210.0
void main() {
// start position of effect
float top = ((resolution.y + EFFECT_HEIGHT) * progress) - EFFECT_HEIGHT;
// current pixel y-coordinate
float p = tex_coord.y * resolution.y;
// calculate alpha value
float alpha = clamp((p - top) / EFFECT_HEIGHT, 0.0, 1.0);
vec3 col = mix(texture(tex, tex_coord).rgb, texture(old, tex_coord).rgb, alpha);
frag_color = vec4(col, 1.0);
}
+52
View File
@@ -0,0 +1,52 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex; // the new scene
uniform sampler2D old; // the old scene
uniform vec2 resolution; // the screen resolution
uniform float progress; // effect progress (0..1)
in vec2 tex_coord;
out vec4 frag_color;
const float PI = 3.14159265;
vec3 get_pixel(vec2 xy, float fade) {
return mix(texture(old, xy).rgb, texture(tex, xy).rgb, fade);
}
void main() {
vec2 p = tex_coord * resolution;
// 1 - (x - 1)^2
float fade_progress = 1.0 - pow(progress - 1.0, 2.0); // (0..0.5..1) -> (0..1) [parabolic]
// sin(PI*x)^4
float blur_size = pow(sin(PI * progress), 4.0); // (0..0.5..1) -> (0..1..0) [sine wave ^ 4]
float blur_half = (blur_size * resolution.x) / 2.0;
vec3 avg = vec3(0.0);
float count = 0.0;
avg += get_pixel(p / resolution, fade_progress);
count++;
for (float i = 1.0; i <= blur_half; i += 2.0) {
avg += get_pixel(vec2(p.x + i, p.y) / resolution, fade_progress);
avg += get_pixel(vec2(p.x - i, p.y) / resolution, fade_progress);
count += 2.0;
}
frag_color = vec4(avg / count, 1.0);
}
+35
View File
@@ -0,0 +1,35 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex; // the new scene
uniform sampler2D old; // the old scene
uniform vec2 resolution; // the screen resolution
uniform float progress; // effect progress (0..1)
in vec2 tex_coord;
out vec4 frag_color;
void main() {
float rand = fract(sin(dot(vec3(tex_coord, progress), vec3(12.9898, 78.233, 81.2463))) * 43758.5453);
vec3 col;
if (progress < 0.5) {
col = mix(texture(old, tex_coord).rgb, vec3(rand), progress * 2.0);
} else {
col = mix(texture(tex, tex_coord).rgb, vec3(rand), (1.0 - progress) * 2.0);
}
frag_color = vec4(col, 1.0);
}
@@ -0,0 +1,36 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex; // the new scene
uniform sampler2D old; // the old scene
uniform vec2 resolution; // the screen resolution
uniform float progress; // effect progress (0..1)
in vec2 tex_coord;
out vec4 frag_color;
void main() {
float rand = fract(sin(dot(vec3(tex_coord, progress), vec3(12.9898, 78.233, 81.2463))) * 43758.5453);
vec3 sepia = rand * vec3(1.0, 0.888, 0.691);
vec3 col;
if (progress < 0.5) {
col = mix(texture(old, tex_coord).rgb, sepia, progress * 2.0);
} else {
col = mix(texture(tex, tex_coord).rgb, sepia, (1.0 - progress) * 2.0);
}
frag_color = vec4(col, 1.0);
}
+74
View File
@@ -0,0 +1,74 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex; // the new scene
uniform sampler2D old; // the old scene
uniform vec2 resolution; // the screen resolution
uniform float progress; // effect progress (0..1)
in vec2 tex_coord;
out vec4 frag_color;
/*
+---------------------+
| . |
| . |
| . |
| . |
| . |
| . |
| p2 +-------+ p4
| | . ,'|
| | ,' |
| | ,' . |
+-------------+'------+
p3 p1
The triangle between p2-p3-p4 contains the old scene mirrored.
The triangle between p1-p3-p4 contains the new scene.
The rest contains the old scene.
p2 moves towards the top-left along the line between p1 and the origin.
*/
void main() {
vec2 p = tex_coord * resolution;
vec2 p1 = resolution;
vec2 p2 = vec2((1.0 - progress*2.0) * p1.x, (1.0 - progress*2.0) * p1.y);
vec2 p3 = vec2(p2.x, resolution.y);
vec2 p4 = vec2(resolution.x, p2.y);
// 1.0 if p is below the line between p3 and p4, else 0.0
float b_below_line = step(0.0, (p4.x - p3.x)*(p.y - p3.y) - (p4.y - p3.y)*(p.x - p3.x));
// bool b_old = p.x < p2.x || p.y < p2.y;
float b_old = step(0.5, step(p.x, p2.x) + step(p.y, p2.y));
// bool b_mirror = !b_old && !b_below_line;
float b_mirror = abs(1.0 - b_old) * abs(1.0 - b_below_line);
// bool b_new = b_below_line;
float b_new = b_below_line;
vec2 p_diff = p - p2;
vec3 c_old = texture(old, tex_coord).rgb;
vec3 c_mirror = texture(old, vec2(p1.x - p_diff.x, p1.y - p_diff.y)/resolution).rgb;
vec3 c_new = texture(tex, tex_coord).rgb;
vec3 col = c_old * b_old + c_mirror * b_mirror + c_new * b_new;
frag_color = vec4(col, 1.0);
}
+27
View File
@@ -0,0 +1,27 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex;
uniform float threshold;
uniform float threshold2;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
float rate = threshold + (threshold2 - threshold) * tex_coord.y;
frag_color = vec4(texture(tex, tex_coord).rgb, rate);
}
+34
View File
@@ -0,0 +1,34 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform vec2 center;
uniform float start_angle;
uniform float angle;
uniform vec4 color;
const float PI = 3.14159265358979323846;
in vec2 tex_coord;
out vec4 frag_color;
void main() {
vec2 p = tex_coord - center;
float a = atan(p.y, p.x);
a = mod(a - start_angle, 2.0 * PI);
if (a > angle)
discard;
frag_color = color;
}
+37
View File
@@ -0,0 +1,37 @@
/* Copyright (C) 2023 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D texture_y;
uniform sampler2D texture_cb;
uniform sampler2D texture_cr;
in vec2 tex_coord;
out vec4 frag_color;
mat4 rec601 = mat4(
1.16438, 0.00000, 1.59603, -0.87079,
1.16438, -0.39176, -0.81297, 0.52959,
1.16438, 2.01723, 0.00000, -1.08139,
0.0, 0.0, 0.0, 1.0
);
void main() {
float y = texture(texture_y, tex_coord).r;
float cb = texture(texture_cb, tex_coord).r;
float cr = texture(texture_cr, tex_coord).r;
frag_color = vec4(y, cb, cr, 1.0) * rec601;
}
+40
View File
@@ -0,0 +1,40 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform sampler2D tex;
uniform float alpha_mod;
uniform vec2 bot_left;
uniform vec2 top_right;
uniform vec3 add_color;
uniform vec3 multiply_color;
in vec2 tex_coord;
out vec4 frag_color;
float point_in_rect(vec2 p, vec2 bot_left, vec2 top_right) {
vec2 s = step(bot_left, p) - step(top_right, p);
return s.x * s.y;
}
void main() {
vec2 size = vec2(textureSize(tex, 0));
vec2 bl = bot_left / size;
vec2 tr = top_right / size;
vec4 tex_color = texture(tex, tex_coord);
vec3 mod_color = (tex_color.rgb + add_color) * multiply_color;
frag_color = vec4(mod_color, tex_color.a * alpha_mod) * point_in_rect(tex_coord, bl, tr);
}
+162
View File
@@ -0,0 +1,162 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#define NR_DIR_LIGHTS 3
#define DIFFUSE_EMISSIVE 0
#define DIFFUSE_NORMAL 1
#define DIFFUSE_LIGHT_MAP 2
#define DIFFUSE_ENV_MAP 3
#define FOG_LINEAR 1
#define FOG_LIGHT_SCATTERING 2
#define ALPHA_BLEND 0
#define ALPHA_TEST 1
#define ALPHA_MAP_BLEND 2
struct dir_light {
vec3 dir;
vec3 diffuse;
vec3 globe_diffuse;
};
uniform sampler2D tex;
uniform sampler2D specular_texture;
uniform sampler2D alpha_texture;
uniform sampler2D light_texture;
uniform sampler2D shadow_texture;
uniform float alpha_mod;
uniform bool use_normal_map;
uniform sampler2D normal_texture;
uniform vec3 ambient;
uniform dir_light dir_lights[NR_DIR_LIGHTS];
uniform float specular_strength;
uniform float specular_shininess;
uniform bool use_specular_map;
uniform float rim_exponent;
uniform vec3 rim_color;
uniform int diffuse_type;
uniform float shadow_darkness;
uniform float shadow_bias;
uniform int fog_type;
uniform float fog_near;
uniform float fog_far;
uniform vec3 fog_color;
uniform int alpha_mode;
in vec2 tex_coord;
in vec2 light_tex_coord;
in vec3 frag_pos;
in vec4 shadow_frag_pos;
in float dist;
in vec3 eye;
in vec3 normal;
in vec3 light_dir[NR_DIR_LIGHTS];
in vec3 specular_dir;
in vec3 ls_ex;
in vec3 ls_in;
out vec4 frag_color;
void main() {
vec3 norm;
if (use_normal_map) {
// NOTE: TT3's shader doesn't normalize this vector.
norm = texture(normal_texture, tex_coord).rgb * 2.0 - 1.0;
} else {
norm = normalize(normal);
}
vec3 view_dir = normalize(eye - frag_pos);
vec3 frag_rgb = ambient;
// Diffuse lighting
vec4 texel;
if (diffuse_type == DIFFUSE_ENV_MAP) {
texel = texture(tex, (vec2(normal.x, -normal.y) + 1.0) / 2.0);
frag_rgb = texel.rgb;
} else {
texel = texture(tex, tex_coord);
if (diffuse_type == DIFFUSE_EMISSIVE) {
frag_rgb = texel.rgb;
} else {
vec3 diffuse = vec3(0.0);
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5;
diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert);
}
if (diffuse_type == DIFFUSE_LIGHT_MAP) {
diffuse *= texture(light_texture, light_tex_coord).rgb;
}
frag_rgb += texel.rgb * diffuse;
}
}
// Specular lighting
if (specular_strength > 0.0) {
vec3 reflect_dir = reflect(specular_dir, norm);
float specular = pow(max(dot(view_dir, reflect_dir), 0.0), specular_shininess) * specular_strength;
if (use_specular_map) {
specular *= texture(specular_texture, tex_coord).r;
}
frag_rgb += vec3(specular);
}
// Rim lighting
if (rim_exponent > 0.0) {
// Normal map is not used here.
vec3 n = use_normal_map ? vec3(0.0, 0.0, 1.0) : normalize(normal);
frag_rgb += pow(1.0 - max(dot(n, view_dir), 0.0), rim_exponent) * rim_color;
}
// Fog
if (fog_type == FOG_LINEAR) {
float fog_factor = clamp((dist - fog_near) / (fog_far - fog_near), 0.0, 1.0);
frag_rgb = mix(frag_rgb, fog_color, fog_factor);
} else if (fog_type == FOG_LIGHT_SCATTERING) {
frag_rgb = frag_rgb * ls_ex + ls_in;
}
// Shadow mapping
if (shadow_darkness > 0.0) {
vec3 shadow_coords = shadow_frag_pos.xyz / shadow_frag_pos.w * 0.5 + 0.5;
shadow_coords.z = min(1.0, shadow_coords.z - shadow_bias);
// PCF with 9 samples.
float brightness = 1.0;
vec2 texel_size = 1.0 / vec2(textureSize(shadow_texture, 0));
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
float depth = texture(shadow_texture, shadow_coords.xy + vec2(x, y) * texel_size).r;
if (depth < shadow_coords.z)
brightness -= 0.05 * shadow_darkness;
}
}
frag_rgb *= brightness;
}
// Alpha mapping
float alpha = texel.a * alpha_mod;
if (alpha_mode == ALPHA_TEST) {
if (alpha < 0.8)
discard;
} else if (alpha_mode == ALPHA_MAP_BLEND) {
alpha *= texture(alpha_texture, tex_coord).r;
}
frag_color = vec4(frag_rgb, alpha);
}
+130
View File
@@ -0,0 +1,130 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#define NR_DIR_LIGHTS 3
#define FOG_LIGHT_SCATTERING 2
const float PI = 3.14159265358979323846;
struct dir_light {
vec3 dir;
vec3 diffuse;
vec3 globe_diffuse;
};
uniform mat4 local_transform;
uniform mat4 view_transform;
uniform mat4 proj_transform;
uniform mat3 normal_transform;
const int MAX_BONES = 211; // see 3d_internal.h
const int NR_WEIGHTS = 4;
uniform bool has_bones;
uniform mat4 bone_matrices[MAX_BONES];
uniform bool use_normal_map;
uniform vec3 camera_pos;
uniform dir_light dir_lights[NR_DIR_LIGHTS];
uniform vec3 specular_light_dir;
uniform mat4 shadow_transform;
uniform int fog_type;
uniform vec4 ls_params; // (beta_r, beta_m, g, distance)
uniform vec3 ls_light_dir;
uniform vec3 ls_light_color;
uniform vec3 ls_sun_color;
in vec3 vertex_pos;
in vec3 vertex_normal;
in vec2 vertex_uv;
in vec2 vertex_light_uv;
in vec4 vertex_tangent;
in ivec4 vertex_bone_index;
in vec4 vertex_bone_weight;
out vec2 tex_coord;
out vec2 light_tex_coord;
out vec3 frag_pos;
out vec4 shadow_frag_pos;
out float dist;
out vec3 eye;
out vec3 normal;
out vec3 light_dir[NR_DIR_LIGHTS];
out vec3 specular_dir;
out vec3 ls_ex;
out vec3 ls_in;
void main() {
mat4 local_bone_transform = local_transform;
mat3 normal_bone_transform = normal_transform;
if (has_bones) {
mat4 bone_transform = mat4(0.f);
for (int i = 0; i < NR_WEIGHTS; i++) {
if (vertex_bone_index[i] >= 0) {
bone_transform += bone_matrices[vertex_bone_index[i]] * vertex_bone_weight[i];
}
}
local_bone_transform *= bone_transform;
normal_bone_transform *= mat3(bone_transform);
}
// World-space normal vector.
normal = normalize(normal_bone_transform * vertex_normal);
mat3 TBN = mat3(1.0f);
if (use_normal_map) {
vec3 tangent = normalize(normal_bone_transform * vertex_tangent.xyz);
vec3 bitangent = cross(normal, tangent) * vertex_tangent.w;
TBN = transpose(mat3(tangent, bitangent, normal));
}
vec4 world_pos = local_bone_transform * vec4(vertex_pos, 1.0);
vec4 view_pos = view_transform * world_pos;
gl_Position = proj_transform * view_pos;
tex_coord = vertex_uv;
light_tex_coord = vertex_light_uv;
dist = -view_pos.z;
shadow_frag_pos = shadow_transform * world_pos;
// These are in tangent-space if use_normal_map is true, in world-space
// otherwise.
frag_pos = TBN * vec3(world_pos);
eye = TBN * camera_pos;
light_dir[0] = TBN * dir_lights[0].dir;
light_dir[1] = TBN * dir_lights[1].dir;
light_dir[2] = TBN * dir_lights[2].dir;
specular_dir = TBN * specular_light_dir;
if (fog_type == FOG_LIGHT_SCATTERING) {
float beta_r = ls_params.x;
float beta_m = ls_params.y;
float g = ls_params.z;
float distance = dist / ls_params.w;
vec3 view_dir = normalize(camera_pos - vec3(world_pos));
float cos_theta = dot(view_dir, normalize(ls_light_dir));
// Note: `* PI` in the two assignments below should be `/ PI` (see the
// definitions of Rayleigh / Mie phase functions in [1]), but this is
// how TT3's shader works.
// [1] http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/ATI-LightScattering.pdf
float phase_r = 3.0 / 16.0 * PI * (1.0 + cos_theta * cos_theta);
float phase_m = 1.0 / 4.0 * PI * (1.0 - g) * (1.0 - g) / pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5);
float f_ex = exp((beta_r + beta_m) * -distance);
ls_in = (phase_r * beta_r + phase_m * beta_m) / (beta_r + beta_m) * (1.0 - f_ex) * ls_sun_color;
ls_ex = ls_light_color * f_ex;
}
}
+21
View File
@@ -0,0 +1,21 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
out uvec4 frag_color;
void main() {
frag_color.r = uint(gl_FragCoord.z * 65535.0);
}
+42
View File
@@ -0,0 +1,42 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
uniform mat4 world_transform;
uniform mat4 view_transform;
const int MAX_BONES = 211; // see 3d_internal.h
const int NR_WEIGHTS = 4;
uniform bool has_bones;
uniform mat4 bone_matrices[MAX_BONES];
in vec3 vertex_pos;
in ivec4 vertex_bone_index;
in vec4 vertex_bone_weight;
void main() {
mat4 world_bone_transform = world_transform;
if (has_bones) {
mat4 bone_transform = mat4(0.f);
for (int i = 0; i < NR_WEIGHTS; i++) {
if (vertex_bone_index[i] >= 0) {
bone_transform += bone_matrices[vertex_bone_index[i]] * vertex_bone_weight[i];
}
}
world_bone_transform *= bone_transform;
}
gl_Position = view_transform * world_bone_transform * vec4(vertex_pos, 1.0);
}
+509
View File
@@ -0,0 +1,509 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#ifndef SYSTEM4_3D_3D_INTERNAL_H
#define SYSTEM4_3D_3D_INTERNAL_H
#include <cglm/types.h>
#include "system4/archive.h"
#include "gfx/gl.h"
#include "gfx/gfx.h"
#include "reign.h"
#define NR_DIR_LIGHTS 3
#define MAX_BONES 211 // Maximum in TT3
typedef struct vec3_range {
vec3 begin;
vec3 end;
} vec3_range;
struct model {
char *path;
int nr_meshes;
struct mesh *meshes;
int nr_materials;
struct material *materials;
int nr_bones;
struct bone *bones;
struct hash_table *bone_map; // bone id in POL/MOT -> struct bone *
struct hash_table *bone_name_map; // bone name -> (struct bone * | NULL)
struct hash_table *mot_cache; // name -> struct mot *
vec3 aabb[2]; // axis-aligned bounding box
bool has_transparent_material;
};
struct mesh {
uint32_t flags;
GLuint vao;
GLuint attr_buffer;
GLuint index_buffer;
int nr_vertices;
int nr_indices;
int material;
};
struct material {
uint32_t flags;
bool is_transparent;
GLuint color_map;
GLuint specular_map;
GLuint alpha_map;
GLuint light_map;
GLuint normal_map;
float specular_strength;
float specular_shininess;
float shadow_darkness;
float rim_exponent;
vec3 rim_color;
};
struct bone {
char *name;
int index; // index on model->bones
int parent; // index on model->bones, or -1
mat4 inverse_bind_matrix;
};
struct motion {
struct RE_instance *instance;
struct mot *mot;
int state;
float current_frame;
float frame_begin, frame_end;
float loop_frame_begin, loop_frame_end;
};
// Attribute variable locations
enum RE_attribute_location {
VATTR_POS = 0,
VATTR_NORMAL,
VATTR_UV,
VATTR_BONE_INDEX,
VATTR_BONE_WEIGHT,
VATTR_LIGHT_UV,
VATTR_TANGENT,
};
struct shadow_renderer {
GLuint program;
GLuint fbo;
GLuint texture;
// Uniform variable locations
GLint world_transform;
GLint view_transform;
GLint has_bones;
GLint bone_matrices;
};
struct RE_renderer {
GLuint program;
GLuint depth_buffer;
struct shadow_renderer shadow;
// Uniform variable locations
GLint world_transform;
GLint view_transform;
GLint texture;
GLint local_transform;
GLint proj_transform;
GLint normal_transform;
GLint alpha_mod;
GLint has_bones;
GLint bone_matrices;
GLint ambient;
struct {
GLint dir;
GLint diffuse;
GLint globe_diffuse;
GLint ambient;
} dir_lights[NR_DIR_LIGHTS];
GLint specular_light_dir;
GLint specular_strength;
GLint specular_shininess;
GLint use_specular_map;
GLint specular_texture;
GLint rim_exponent;
GLint rim_color;
GLint camera_pos;
GLint diffuse_type;
GLint light_texture;
GLint use_normal_map;
GLint normal_texture;
GLint shadow_darkness;
GLint shadow_transform;
GLint shadow_texture;
GLint shadow_bias;
GLint fog_type;
GLint fog_near;
GLint fog_far;
GLint fog_color;
GLint ls_params;
GLint ls_light_dir;
GLint ls_light_color;
GLint ls_sun_color;
GLint alpha_mode;
GLint alpha_texture;
GLuint billboard_vao;
GLuint billboard_attr_buffer;
struct hash_table *billboard_textures; // cg_no -> struct billboard_texture*
};
struct billboard_texture {
GLuint texture;
bool has_alpha;
};
// reign.c
void RE_instance_update_local_transform(struct RE_instance *inst);
// model.c
struct model *model_load(struct archive *aar, const char *path);
void model_free(struct model *model);
struct model *model_create_sphere(int r, int g, int b, int a);
struct motion *motion_load(const char *name, struct RE_instance *instance, struct archive *aar);
void motion_free(struct motion *motion);
struct archive_data *RE_get_aar_entry(struct archive *aar, const char *dir, const char *name, const char *ext);
// renderer.c
struct RE_renderer *RE_renderer_new(struct texture *texture);
void RE_renderer_free(struct RE_renderer *r);
bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no);
struct height_detector *RE_renderer_create_height_detector(struct RE_renderer *r, struct model *model);
void RE_renderer_free_height_detector(struct height_detector *hd);
bool RE_renderer_detect_height(struct height_detector *hd, float x, float z, float *y_out);
void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out);
// particle.c
enum particle_type {
PARTICLE_TYPE_BILLBOARD = 0,
PARTICLE_TYPE_POLYGON_OBJECT = 1,
PARTICLE_TYPE_SWORD_BLUR = 2,
PARTICLE_TYPE_CAMERA_QUAKE = 3,
};
enum particle_move_type {
PARTICLE_MOVE_FIXED = 0,
PARTICLE_MOVE_LINEAR = 1,
PARTICLE_MOVE_EMITTER = 2,
};
enum particle_up_vector_type {
PARTICLE_UP_VECTOR_Y_AXIS = 0,
PARTICLE_UP_VECTOR_OBJECT_MOVE = 1,
PARTICLE_UP_VECTOR_INSTANCE_MOVE = 2,
PARTICLE_UP_VECTOR_TYPE_MAX = PARTICLE_UP_VECTOR_INSTANCE_MOVE
};
enum particle_blend_type {
PARTICLE_BLEND_NORMAL = 0,
PARTICLE_BLEND_ADDITIVE = 1,
};
enum particle_frame_ref_type {
PARTICLE_FRAME_REF_EFFECT = 0,
PARTICLE_FRAME_REF_TARGET = 1,
};
enum particle_child_move_dir_type {
PARTICLE_CHILD_MOVE_DIR_NORMAL = 0,
PARTICLE_CHILD_MOVE_DIR_REVERSE = 1,
PARTICLE_CHILD_MOVE_DIR_TYPE_MAX = PARTICLE_CHILD_MOVE_DIR_REVERSE
};
enum particle_dir_type {
PARTICLE_DIR_TYPE_NORMAL = 0,
PARTICLE_DIR_TYPE_XY_PLANE = 1,
PARTICLE_DIR_TYPE_MAX = PARTICLE_DIR_TYPE_XY_PLANE
};
struct particle_position_unit {
enum {
PARTICLE_POS_UNIT_NONE = 0,
PARTICLE_POS_UNIT_TARGET = 1,
PARTICLE_POS_UNIT_BONE = 2,
PARTICLE_POS_UNIT_RAND = 4,
PARTICLE_POS_UNIT_RAND_POSITIVE_Y = 5,
PARTICLE_POS_UNIT_ABSOLUTE = 6,
} type;
union {
struct {
int index;
vec3 offset;
} target;
struct {
int target_index;
char *name;
vec3 offset;
} bone;
struct {
float f;
} rand;
vec3 absolute;
};
};
#define NR_PARTICLE_POSITIONS 2
#define NR_PARTICLE_POSITION_UNITS 3
struct particle_position {
struct particle_position_unit units[NR_PARTICLE_POSITION_UNITS];
};
struct pae {
char *path;
struct hash_table *textures; // name -> struct billboard_texture*
int nr_objects;
struct pae_object *objects;
};
struct pae_object {
char *name;
enum particle_type type;
enum particle_move_type move_type;
enum particle_up_vector_type up_vector_type;
float move_curve;
struct particle_position *position[NR_PARTICLE_POSITIONS];
float size[2];
int nr_sizes2;
float *sizes2;
int nr_sizes_x;
float *sizes_x;
int nr_sizes_y;
float *sizes_y;
int nr_size_types;
int *size_types;
int nr_size_x_types;
int *size_x_types;
int nr_size_y_types;
int *size_y_types;
int nr_textures;
char **textures;
enum particle_blend_type blend_type;
float texture_anime_frame;
int texture_anime_time;
char *polygon_name;
int begin_frame;
int end_frame;
int stop_frame;
enum particle_frame_ref_type frame_ref_type;
int frame_ref_param;
int nr_particles;
float alpha_fadein_frame;
int alpha_fadein_time;
float alpha_fadeout_frame;
int alpha_fadeout_time;
vec3_range rotation;
vec3_range revolution_angle;
vec3_range revolution_distance;
vec3 curve_length;
int child_frame;
float child_length;
float child_begin_slope;
float child_end_slope;
float child_create_begin_frame;
float child_create_end_frame;
enum particle_child_move_dir_type child_move_dir_type;
enum particle_dir_type dir_type;
int nr_damages;
int *damages;
float offset_x;
float offset_y;
struct model *model;
};
struct particle_effect {
struct pae *pae;
struct particle_object *objects; // pae->nr_objects elements
bool camera_quake_enabled;
};
struct particle_object {
struct pae_object *pae_obj;
struct particle_instance *instances; // pae_obj->nr_particles elements
vec3_range pos;
vec3 move_vec, move_ortho;
};
struct particle_instance {
float begin_frame;
float end_frame;
vec3_range random_offset;
float roll_angle;
float pitch_angle;
};
struct pae *pae_load(struct archive *aar, const char *path);
void pae_free(struct pae *pae);
void pae_calc_frame_range(struct pae *pae, struct motion *motion);
float pae_object_calc_alpha(struct pae_object *po, struct particle_instance *pi, float frame);
struct particle_effect *particle_effect_create(struct pae *pae);
void particle_effect_free(struct particle_effect *effect);
void particle_effect_update(struct RE_instance *inst);
void particle_object_calc_local_transform(struct RE_instance *inst, struct particle_object *po, struct particle_instance *pi, float frame, mat4 dest);
// parser.c
struct pol {
int32_t version;
uint32_t nr_materials;
struct pol_material_group *materials;
uint32_t nr_meshes;
struct pol_mesh **meshes;
uint32_t nr_bones;
struct pol_bone *bones;
};
enum pol_texture_type {
COLOR_MAP = 1,
SPECULAR_MAP = 4,
ALPHA_MAP = 6,
LIGHT_MAP = 7,
NORMAL_MAP = 8,
MAX_TEXTURE_TYPE
};
enum material_flags {
MATERIAL_SPRITE = 1 << 0,
};
struct pol_material {
char *name;
uint32_t flags;
char *textures[MAX_TEXTURE_TYPE];
};
struct pol_material_group {
struct pol_material m;
uint32_t nr_children;
struct pol_material *children;
};
enum mesh_flags {
MESH_NOLIGHTING = 1 << 0,
MESH_NOMAKESHADOW = 1 << 1,
MESH_ENVMAP = 1 << 2,
MESH_BOTH = 1 << 3,
MESH_SPRITE = 1 << 4,
};
struct pol_mesh {
char *name;
uint32_t flags;
uint32_t material;
uint32_t nr_vertices;
struct pol_vertex *vertices;
uint32_t nr_uvs;
vec2 *uvs;
uint32_t nr_light_uvs;
vec2 *light_uvs;
uint32_t nr_triangles;
struct pol_triangle *triangles;
};
struct pol_vertex {
vec3 pos;
uint32_t nr_weights;
struct pol_bone_weight *weights;
};
struct pol_bone_weight {
uint32_t bone;
float weight;
};
struct pol_triangle {
uint32_t vert_index[3];
uint32_t uv_index[3];
uint32_t light_uv_index[3];
vec3 normals[3];
uint32_t material_group_index;
};
struct pol_bone {
char *name;
uint32_t id;
int32_t parent;
vec3 pos;
versor rotq;
};
struct mot {
char *name;
uint32_t nr_frames;
uint32_t nr_bones;
struct mot_bone *motions[];
};
struct mot_frame {
vec3 pos;
versor rotq;
};
struct mot_bone {
char *name;
uint32_t id;
uint32_t parent;
struct mot_frame frames[];
};
struct amt {
int version;
int nr_materials;
struct amt_material *materials[];
};
struct amt_material {
char *name;
float fields[];
};
enum amt_field_index {
AMT_SPECULAR_STRENGTH = 0,
AMT_SPECULAR_SHININESS = 2,
// amt v4+
AMT_SHADOW_DARKNESS = 6,
// amt v5+
AMT_RIM_EXPONENT = 7,
AMT_RIM_R = 8,
AMT_RIM_G = 9,
AMT_RIM_B = 10,
};
struct pol *pol_parse(uint8_t *data, size_t size);
void pol_free(struct pol *pol);
void pol_compute_aabb(struct pol *model, vec3 dest[2]);
struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id);
struct mot *mot_parse(uint8_t *data, size_t size, const char *name);
void mot_free(struct mot *mot);
struct amt *amt_parse(uint8_t *data, size_t size);
void amt_free(struct amt *amt);
struct amt_material *amt_find_material(struct amt *amt, const char *name);
#endif /* SYSTEM4_3D_3D_INTERNAL_H */
+163
View File
@@ -0,0 +1,163 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include "system4/string.h"
#include "3d_internal.h"
#include "reign.h"
#include "sprite.h"
#include "xsystem4.h"
#define SPREAD_VEC3(v) (v)[0], (v)[1], (v)[2]
static const char *instance_type_name(enum RE_instance_type type)
{
switch (type) {
case RE_ITYPE_UNINITIALIZED: return "UNINITIALIZED";
case RE_ITYPE_STATIC: return "STATIC";
case RE_ITYPE_SKINNED: return "SKINNED";
case RE_ITYPE_BILLBOARD: return "BILLBOARD";
case RE_ITYPE_DIRECTIONAL_LIGHT: return "DIRECTIONAL_LIGHT";
case RE_ITYPE_SPECULAR_LIGHT: return "SPECULAR_LIGHT";
case RE_ITYPE_PARTICLE_EFFECT: return "PARTICLE_EFFECT";
}
return "UNKNOWN";
}
static const char *motion_state_name(enum RE_motion_state state)
{
switch (state) {
case RE_MOTION_STATE_STOP: return "STOP";
case RE_MOTION_STATE_NOLOOP: return "NOLOOP";
case RE_MOTION_STATE_LOOP: return "LOOP";
}
return "UNKNOWN";
}
static const char *fog_type_name(enum RE_fog_type type)
{
switch (type) {
case RE_FOG_NONE: return "NONE";
case RE_FOG_LINEAR: return "LINEAR";
case RE_FOG_LIGHT_SCATTERING: return "LIGHT_SCATTERING";
}
return "UNKNOWN";
}
static void print_motion(const char *name, struct motion *m, int indent)
{
if (m->instance->type == RE_ITYPE_BILLBOARD) {
indent_printf(indent, "%s = {state=%s, frame=%f, range=(%d,%d), loop_range=(%d,%d)},\n",
name, motion_state_name(m->state), m->current_frame,
(int)m->frame_begin, (int)m->frame_end, (int)m->loop_frame_begin, (int)m->loop_frame_end);
} else if (m->mot) {
indent_printf(indent, "%s = {name=\"%s\", state=%s, frame=%f},\n",
name, m->mot->name, motion_state_name(m->state), m->current_frame);
}
}
static void print_instance(struct RE_instance *inst, int index, int indent)
{
if (!inst)
return;
indent_printf(indent, "instance[%d] = {\n", index);
indent++;
indent_printf(indent, "type = %s,\n", instance_type_name(inst->type));
if (inst->type == RE_ITYPE_DIRECTIONAL_LIGHT || inst->type == RE_ITYPE_SPECULAR_LIGHT) {
indent_printf(indent, "vec = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->vec));
indent_printf(indent, "diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->diffuse));
indent_printf(indent, "globe_diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->globe_diffuse));
} else {
indent_printf(indent, "draw = %d,\n", inst->draw);
indent_printf(indent, "pos = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->pos));
indent_printf(indent, "scale = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->scale));
indent_printf(indent, "ambient = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->ambient));
}
if (inst->model) {
indent_printf(indent, "path = \"%s\",\n", inst->model->path);
indent_printf(indent, "aabb = {min = {x=%f, y=%f, z=%f}, max = {x=%f, y=%f, z=%f}},\n",
SPREAD_VEC3(inst->model->aabb[0]), SPREAD_VEC3(inst->model->aabb[1]));
}
if (inst->motion) {
indent_printf(indent, "fps = %f,\n", inst->fps);
print_motion("motion", inst->motion, indent);
}
if (inst->next_motion)
print_motion("next_motion", inst->next_motion, indent);
if (inst->motion_blend)
indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate);
if (inst->effect)
indent_printf(indent, "path = \"%s\",\n", inst->effect->pae->path);
indent--;
indent_printf(indent, "},\n");
}
static void print_back_cg(struct RE_back_cg *bcg, int index, int indent)
{
if (!bcg->name && !bcg->no)
return;
indent_printf(indent, "backCG[%d] = {\n", index);
indent++;
if (bcg->no)
indent_printf(indent, "no = %d,\n", bcg->no);
if (bcg->name)
indent_printf(indent, "name = \"%s\",\n", bcg->name ? bcg->name->text : "");
indent_printf(indent, "pos = {x=%f, y=%f},\n", bcg->x, bcg->y);
indent_printf(indent, "blend_rate = %f,\n", bcg->blend_rate);
indent_printf(indent, "mag = %f,\n", bcg->mag);
indent_printf(indent, "show = %d,\n", bcg->show);
indent--;
indent_printf(indent, "},\n");
}
void RE_debug_print(struct sact_sprite *sp, int indent)
{
struct RE_plugin *p = (struct RE_plugin *)sp->plugin;
indent_printf(indent, "name = \"%s\",\n", p->plugin.name);
indent_printf(indent, "camera = {x=%f, y=%f, z=%f, pitch=%f, roll=%f, yaw=%f},\n",
SPREAD_VEC3(p->camera.pos), p->camera.pitch, p->camera.roll, p->camera.yaw);
indent_printf(indent, "shadow_map_light_dir = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(p->shadow_map_light_dir));
indent_printf(indent, "shadow_bias = %f,\n", p->shadow_bias);
indent_printf(indent, "fog_type = %s,\n", fog_type_name(p->fog_type));
switch (p->fog_type) {
case RE_FOG_NONE:
break;
case RE_FOG_LINEAR:
indent_printf(indent, "fog_near = %f, fog_far = %f,\n", p->fog_near, p->fog_far);
indent_printf(indent, "fog_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->fog_color));
break;
case RE_FOG_LIGHT_SCATTERING:
indent_printf(indent, "ls_beta_r = %f, ls_beta_m = %f,\n", p->ls_beta_r, p->ls_beta_m);
indent_printf(indent, "ls_g = %f,\n", p->ls_g);
indent_printf(indent, "ls_distance = %f,\n", p->ls_distance);
indent_printf(indent, "ls_light_dir = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(p->ls_light_dir));
indent_printf(indent, "ls_light_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->ls_light_color));
indent_printf(indent, "ls_sun_color = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(p->ls_sun_color));
break;
}
for (int i = 0; i < p->nr_instances; i++)
print_instance(p->instances[i], i, indent);
for (int i = 0; i < RE_NR_BACK_CGS; i++)
print_back_cg(&p->back_cg[i], i, indent);
}
+668
View File
@@ -0,0 +1,668 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <cglm/cglm.h>
#include "system4.h"
#include "system4/aar.h"
#include "system4/cg.h"
#include "system4/hashtable.h"
#include "3d_internal.h"
#include "reign.h"
#define FP16_MIN 6.103516e-5f
#define NR_WEIGHTS 4
struct vertex_common {
GLfloat pos[3];
GLfloat normal[3];
GLfloat uv[2];
};
struct vertex_light_uv {
GLfloat uv[2];
};
struct vertex_tangent {
GLfloat tangent[4];
};
struct vertex_bones {
GLint bone_id[NR_WEIGHTS];
GLfloat bone_weight[NR_WEIGHTS];
};
struct archive_data *RE_get_aar_entry(struct archive *aar, const char *dir, const char *name, const char *ext)
{
char *path = xmalloc(strlen(dir) + strlen(name) + strlen(ext) + 2);
sprintf(path, "%s\\%s%s", dir, name, ext);
struct archive_data *dfile = archive_get_by_name(aar, path);
free(path);
return dfile;
}
static GLuint load_texture(struct archive *aar, const char *path, const char *name, bool *has_alpha_out)
{
struct archive_data *dfile = RE_get_aar_entry(aar, path, name, "");
if (!dfile) {
WARNING("cannot load texture %s\\%s", path, name);
return 0;
}
struct cg *cg = cg_load_data(dfile);
if (!cg) {
WARNING("cg_load_data failed: %s", dfile->name);
archive_free_data(dfile);
return 0;
}
archive_free_data(dfile);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
if (has_alpha_out)
*has_alpha_out = cg->metrics.has_alpha;
cg_free(cg);
return texture;
}
static bool init_material(struct material *material, const struct pol_material *m, struct amt *amt, struct archive *aar, const char *path)
{
material->flags = m->flags;
if (!m->textures[COLOR_MAP]) {
WARNING("No color texture");
return false;
}
bool has_alpha;
material->color_map = load_texture(aar, path, m->textures[COLOR_MAP], &has_alpha);
if (!material->color_map)
return false;
if (m->textures[SPECULAR_MAP])
material->specular_map = load_texture(aar, path, m->textures[SPECULAR_MAP], NULL);
if (m->textures[ALPHA_MAP])
material->alpha_map = load_texture(aar, path, m->textures[ALPHA_MAP], NULL);
if (m->textures[LIGHT_MAP])
material->light_map = load_texture(aar, path, m->textures[LIGHT_MAP], NULL);
if (m->textures[NORMAL_MAP])
material->normal_map = load_texture(aar, path, m->textures[NORMAL_MAP], NULL);
material->is_transparent = (has_alpha || material->alpha_map) && !(material->flags & MATERIAL_SPRITE);
material->shadow_darkness = 1.0f;
struct amt_material *amt_m = amt ? amt_find_material(amt, m->name) : NULL;
if (amt_m) {
material->specular_strength = amt_m->fields[AMT_SPECULAR_STRENGTH];
material->specular_shininess = amt_m->fields[AMT_SPECULAR_SHININESS];
if (amt->version >= 4)
material->shadow_darkness = amt_m->fields[AMT_SHADOW_DARKNESS];
if (amt->version >= 5) {
material->rim_exponent = amt_m->fields[AMT_RIM_EXPONENT];
material->rim_color[0] = amt_m->fields[AMT_RIM_R];
material->rim_color[1] = amt_m->fields[AMT_RIM_G];
material->rim_color[2] = amt_m->fields[AMT_RIM_B];
// Very small rim_exponent value should not be used for rim
// lighting. (e.g. meizi.amt in TT3)
if (material->rim_exponent < FP16_MIN)
material->rim_exponent = 0.0f;
}
}
return true;
}
static void destroy_material(struct material *material)
{
if (material->color_map)
glDeleteTextures(1, &material->color_map);
if (material->specular_map)
glDeleteTextures(1, &material->specular_map);
if (material->alpha_map)
glDeleteTextures(1, &material->alpha_map);
if (material->light_map)
glDeleteTextures(1, &material->light_map);
if (material->normal_map)
glDeleteTextures(1, &material->normal_map);
}
static int cmp_by_bone_weight(const void *lhs, const void *rhs)
{
float l = ((struct pol_bone_weight *)lhs)->weight;
float r = ((struct pol_bone_weight *)rhs)->weight;
return (l < r) - (l > r); // descending order.
}
static void sort_and_normalize_bone_weights(struct pol_vertex *v)
{
qsort(v->weights, v->nr_weights, sizeof(struct pol_bone_weight), cmp_by_bone_weight);
float total = 0.0;
for (uint32_t i = 0; i < v->nr_weights && i < NR_WEIGHTS; i++) {
total += v->weights[i].weight;
}
for (uint32_t i = 0; i < v->nr_weights && i < NR_WEIGHTS; i++) {
v->weights[i].weight /= total;
}
}
static void calc_tangent(struct pol_mesh *m, struct pol_triangle *t, vec4 tangent[3])
{
vec3 v1, v2;
glm_vec3_sub(m->vertices[t->vert_index[1]].pos, m->vertices[t->vert_index[0]].pos, v1);
glm_vec3_sub(m->vertices[t->vert_index[2]].pos, m->vertices[t->vert_index[0]].pos, v2);
vec2 w1, w2;
glm_vec2_sub(m->uvs[t->uv_index[1]], m->uvs[t->uv_index[0]], w1);
glm_vec2_sub(m->uvs[t->uv_index[2]], m->uvs[t->uv_index[0]], w2);
float r = 1.0 / (w1[0] * w2[1] - w2[0] * w1[1]);
if (!isfinite(r)) // degenerate uv triangle
r = 1.0; // ??
vec3 sdir, tdir;
glm_vec3_scale(v1, w2[1], sdir);
glm_vec3_muladds(v2, -w1[1], sdir);
glm_vec3_scale(sdir, r, sdir);
glm_vec3_scale(v2, w1[0], tdir);
glm_vec3_muladds(v1, -w2[0], tdir);
glm_vec3_scale(tdir, r, tdir);
for (int i = 0; i < 3; i++) {
vec3 s;
glm_vec3_copy(sdir, s);
// Gram-Schmidt orthogonalize.
glm_vec3_muladds(t->normals[i], -glm_vec3_dot(t->normals[i], s), s);
glm_vec3_normalize(s);
// Calculate handedness.
vec3 c;
glm_vec3_cross(t->normals[i], sdir, c);
float w = (glm_vec3_dot(c, tdir) < 0.0) ? -1.0 : 1.0;
glm_vec4(s, w, tangent[i]);
}
}
static void *buf_alloc(uint8_t **ptr, int size)
{
void *p = *ptr;
*ptr += size;
return p;
}
static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_group_index, int material)
{
bool has_light_map = m->light_uvs && model->materials[material].light_map;
bool has_normal_map = model->materials[material].normal_map != 0;
bool has_bones = !!model->bone_map;
GLsizei stride = sizeof(struct vertex_common);
if (has_light_map)
stride += sizeof(struct vertex_light_uv);
if (has_normal_map)
stride += sizeof(struct vertex_tangent);
if (has_bones)
stride += sizeof(struct vertex_bones);
void *buffer = xmalloc(m->nr_triangles * 3 * stride);
uint8_t *ptr = buffer;
int nr_vertices = 0;
for (uint32_t i = 0; i < m->nr_triangles; i++) {
struct pol_triangle *t = &m->triangles[i];
if (t->material_group_index != material_group_index)
continue;
vec4 tangent[3];
if (has_normal_map)
calc_tangent(m, t, tangent);
for (int j = 0; j < 3; j++) {
struct pol_vertex *vert = &m->vertices[t->vert_index[j]];
struct vertex_common *v_common = buf_alloc(&ptr, sizeof(struct vertex_common));
glm_vec3_copy(vert->pos, v_common->pos);
glm_vec3_copy(t->normals[j], v_common->normal);
glm_vec2_copy(m->uvs[t->uv_index[j]], v_common->uv);
if (has_light_map) {
struct vertex_light_uv *v_light_uv = buf_alloc(&ptr, sizeof(struct vertex_light_uv));
glm_vec2_copy(m->light_uvs[t->light_uv_index[j]], v_light_uv->uv);
}
if (has_normal_map) {
struct vertex_tangent *v_tangent = buf_alloc(&ptr, sizeof(struct vertex_tangent));
glm_vec4_ucopy(tangent[j], v_tangent->tangent);
}
if (has_bones) {
struct vertex_bones *v_bones = buf_alloc(&ptr, sizeof(struct vertex_bones));
sort_and_normalize_bone_weights(vert);
for (uint32_t k = 0; k < NR_WEIGHTS; k++) {
if (k < vert->nr_weights) {
struct bone *bone = ht_get_int(model->bone_map, vert->weights[k].bone, NULL);
if (!bone)
WARNING("%s: invalid bone id in vertex data", model->path);
v_bones->bone_id[k] = bone ? bone->index : -1;
v_bones->bone_weight[k] = vert->weights[k].weight;
} else {
v_bones->bone_id[k] = -1;
v_bones->bone_weight[k] = 0.0;
}
}
}
nr_vertices++;
}
}
assert(ptr == (uint8_t *)buffer + nr_vertices * stride);
if (nr_vertices == 0) {
free(buffer);
return;
}
model->meshes = xrealloc_array(model->meshes, model->nr_meshes, model->nr_meshes + 1, sizeof(struct mesh));
struct mesh *mesh = &model->meshes[model->nr_meshes++];
mesh->flags = m->flags;
mesh->material = material;
mesh->nr_vertices = nr_vertices;
glGenVertexArrays(1, &mesh->vao);
glBindVertexArray(mesh->vao);
glGenBuffers(1, &mesh->attr_buffer);
glBindBuffer(GL_ARRAY_BUFFER, mesh->attr_buffer);
const uint8_t *base = (const uint8_t *)0;
glEnableVertexAttribArray(VATTR_POS);
glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, pos));
glEnableVertexAttribArray(VATTR_NORMAL);
glVertexAttribPointer(VATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, normal));
glEnableVertexAttribArray(VATTR_UV);
glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, uv));
base += sizeof(struct vertex_common);
if (has_light_map) {
glEnableVertexAttribArray(VATTR_LIGHT_UV);
glVertexAttribPointer(VATTR_LIGHT_UV, 2, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_light_uv, uv));
base += sizeof(struct vertex_light_uv);
} else {
glDisableVertexAttribArray(VATTR_LIGHT_UV);
glVertexAttrib2f(VATTR_LIGHT_UV, 0.0, 0.0);
}
if (has_normal_map) {
glEnableVertexAttribArray(VATTR_TANGENT);
glVertexAttribPointer(VATTR_TANGENT, 4, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_tangent, tangent));
base += sizeof(struct vertex_tangent);
} else {
glDisableVertexAttribArray(VATTR_TANGENT);
glVertexAttrib3f(VATTR_TANGENT, 1.0, 0.0, 0.0);
}
if (has_bones) {
glEnableVertexAttribArray(VATTR_BONE_INDEX);
glVertexAttribIPointer(VATTR_BONE_INDEX, NR_WEIGHTS, GL_INT, stride, base + offsetof(struct vertex_bones, bone_id));
glEnableVertexAttribArray(VATTR_BONE_WEIGHT);
glVertexAttribPointer(VATTR_BONE_WEIGHT, NR_WEIGHTS, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_bones, bone_weight));
base += sizeof(struct vertex_bones);
} else {
glDisableVertexAttribArray(VATTR_BONE_INDEX);
glVertexAttribI4i(VATTR_BONE_INDEX, 0, 0, 0, 0);
glDisableVertexAttribArray(VATTR_BONE_WEIGHT);
glVertexAttrib4f(VATTR_BONE_WEIGHT, 0.0, 0.0, 0.0, 0.0);
}
assert((intptr_t)base == stride);
glBufferData(GL_ARRAY_BUFFER, mesh->nr_vertices * stride, buffer, GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
free(buffer);
}
static void destroy_mesh(struct mesh *mesh)
{
glDeleteVertexArrays(1, &mesh->vao);
glDeleteBuffers(1, &mesh->attr_buffer);
if (mesh->index_buffer)
glDeleteBuffers(1, &mesh->index_buffer);
}
static struct bone *add_bone(struct model *model, struct pol *pol, struct pol_bone *pol_bone)
{
struct bone *bone = ht_get_int(model->bone_map, pol_bone->id, NULL);
if (bone)
return bone; // already added.
struct bone *parent = NULL;
if (pol_bone->parent >= 0) {
// Parent bone must appear before its children in model->bones.
struct pol_bone *pol_parent = pol_find_bone(pol, pol_bone->parent);
if (!pol_parent)
ERROR("Parent bone of \"%s\" is not found", pol_bone->name);
parent = add_bone(model, pol, pol_parent);
}
bone = &model->bones[model->nr_bones];
ht_put_int(model->bone_map, pol_bone->id, bone);
bone->name = strdup(pol_bone->name);
bone->index = model->nr_bones;
bone->parent = parent ? parent->index : -1;
glm_quat_mat4(pol_bone->rotq, bone->inverse_bind_matrix);
glm_translate(bone->inverse_bind_matrix, pol_bone->pos);
// Update bone_name_map. If the bone name is not unique in the POL, set the
// map value to NULL so that ID matching will be used.
struct ht_slot *slot = ht_put(model->bone_name_map, pol_bone->name, bone);
if (slot->value != bone) {
NOTICE("%s: non-unique bone %s", model->path, pol_bone->name);
slot->value = NULL;
}
model->nr_bones++;
return bone;
}
static void destroy_bone(struct bone *bone)
{
free(bone->name);
}
struct model *model_load(struct archive *aar, const char *path)
{
const char *basename = strrchr(path, '\\');
basename = basename ? basename + 1 : path;
// Load .POL file
struct archive_data *pol_file = RE_get_aar_entry(aar, path, basename, ".POL");
if (!pol_file) {
WARNING("%s\\%s.POL: not found", path, basename);
return NULL;
}
struct pol *pol = pol_parse(pol_file->data, pol_file->size);
if (!pol) {
WARNING("%s: parse error", pol_file->name);
archive_free_data(pol_file);
return NULL;
}
archive_free_data(pol_file);
// Load .amt file, if any
struct amt *amt = NULL;
struct archive_data *amt_file = RE_get_aar_entry(aar, path, basename, ".amt");
if (amt_file) {
amt = amt_parse(amt_file->data, amt_file->size);
if (!amt)
WARNING("%s: parse error", amt_file->name);
archive_free_data(amt_file);
}
struct model *model = xcalloc(1, sizeof(struct model));
model->path = strdup(path);
// Bones
if (pol->nr_bones > 0) {
if (pol->nr_bones > MAX_BONES)
ERROR("%s: Too many bones (%u)", model->path, pol->nr_bones);
model->bone_map = ht_create(pol->nr_bones * 3 / 2);
model->bone_name_map = ht_create(pol->nr_bones * 3 / 2);
model->mot_cache = ht_create(16);
model->bones = xcalloc(pol->nr_bones, sizeof(struct bone));
for (uint32_t i = 0; i < pol->nr_bones; i++) {
add_bone(model, pol, &pol->bones[i]);
}
if (model->nr_bones != (int)pol->nr_bones)
ERROR("%s: Broken bone data", model->path);
}
// Materials
int *material_offsets = xmalloc(pol->nr_materials * sizeof(int));
for (uint32_t i = 0; i < pol->nr_materials; i++) {
material_offsets[i] = model->nr_materials;
if (pol->materials[i].nr_children)
model->nr_materials += pol->materials[i].nr_children;
else
model->nr_materials++;
}
model->materials = xcalloc(model->nr_materials, sizeof(struct material));
for (uint32_t i = 0; i < pol->nr_materials; i++) {
if (pol->materials[i].nr_children == 0) {
init_material(&model->materials[material_offsets[i]],
&pol->materials[i].m, amt, aar, path);
continue;
}
for (uint32_t j = 0; j < pol->materials[i].nr_children; j++) {
init_material(&model->materials[material_offsets[i] + j],
&pol->materials[i].children[j], amt, aar, path);
}
}
for (int i = 0; i < model->nr_materials; i++) {
if (model->materials[i].is_transparent) {
model->has_transparent_material = true;
break;
}
}
// Meshes
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
if (!pol->meshes[i])
continue;
struct pol_material_group *mg = &pol->materials[pol->meshes[i]->material];
int m_off = material_offsets[pol->meshes[i]->material];
if (mg->nr_children == 0) {
add_mesh(model, pol->meshes[i], 0, m_off);
continue;
}
for (uint32_t j = 0; j < mg->nr_children; j++) {
add_mesh(model, pol->meshes[i], j, m_off + j);
}
}
pol_compute_aabb(pol, model->aabb);
free(material_offsets);
if (amt)
amt_free(amt);
pol_free(pol);
return model;
}
void model_free(struct model *model)
{
for (int i = 0; i < model->nr_meshes; i++)
destroy_mesh(&model->meshes[i]);
free(model->meshes);
for (int i = 0; i < model->nr_materials; i++)
destroy_material(&model->materials[i]);
free(model->materials);
for (int i = 0; i < model->nr_bones; i++)
destroy_bone(&model->bones[i]);
free(model->bones);
if (model->bone_map)
ht_free_int(model->bone_map);
if (model->bone_name_map)
ht_free(model->bone_name_map);
if (model->mot_cache) {
ht_foreach_value(model->mot_cache, (void(*)(void*))mot_free);
ht_free(model->mot_cache);
}
free(model->path);
free(model);
}
static void init_sphere_mesh(struct mesh *mesh)
{
const int w_segments = 16;
const int h_segments = 16;
const int nr_vertices = (w_segments + 1) * (h_segments + 1);
struct vertex_common *vertices = xcalloc(nr_vertices, sizeof(struct vertex_common));
struct vertex_common *v = vertices;
for (int y = 0; y <= h_segments; y++) {
float theta = GLM_PIf * y / h_segments;
for (int x = 0; x <= w_segments; x++, v++) {
float phi = 2.0f * GLM_PIf * x / w_segments;
v->pos[0] = -cosf(phi) * sinf(theta);
v->pos[1] = cosf(theta);
v->pos[2] = sinf(phi) * sinf(theta);
glm_vec3_copy(v->pos, v->normal);
v->uv[0] = v->uv[1] = 0.0f;
}
}
assert(v == vertices + nr_vertices);
const int nr_indices = 3 * 2 * w_segments * (h_segments - 1);
GLushort *indices = xcalloc(nr_indices, sizeof(GLushort));
GLushort *pi = indices;
for (int y = 0; y < h_segments; y++) {
for (int x = 0; x < w_segments; x++) {
GLushort a = y * w_segments + x + 1;
GLushort b = y * w_segments + x;
GLushort c = (y + 1) * w_segments + x;
GLushort d = (y + 1) * w_segments + x + 1;
if (y > 0) {
*pi++ = a;
*pi++ = b;
*pi++ = d;
}
if (y < h_segments - 1) {
*pi++ = b;
*pi++ = c;
*pi++ = d;
}
}
}
assert(pi == indices + nr_indices);
mesh->flags = MESH_NOLIGHTING;
mesh->nr_vertices = nr_vertices;
mesh->nr_indices = nr_indices;
glGenVertexArrays(1, &mesh->vao);
glBindVertexArray(mesh->vao);
glGenBuffers(1, &mesh->attr_buffer);
glBindBuffer(GL_ARRAY_BUFFER, mesh->attr_buffer);
glBufferData(GL_ARRAY_BUFFER, nr_vertices * sizeof(struct vertex_common), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(VATTR_POS);
glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex_common), (void*)offsetof(struct vertex_common, pos));
glEnableVertexAttribArray(VATTR_NORMAL);
glVertexAttribPointer(VATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex_common), (void*)offsetof(struct vertex_common, normal));
glEnableVertexAttribArray(VATTR_UV);
glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex_common), (void*)offsetof(struct vertex_common, uv));
glGenBuffers(1, &mesh->index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->index_buffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, nr_indices * sizeof(GLushort), indices, GL_STATIC_DRAW);
glBindVertexArray(0);
free(vertices);
free(indices);
}
struct model *model_create_sphere(int r, int g, int b, int a)
{
struct model *model = xcalloc(1, sizeof(struct model));
model->nr_meshes = 1;
model->meshes = xcalloc(1, sizeof(struct mesh));
init_sphere_mesh(&model->meshes[0]);
model->aabb[0][0] = -1.0f;
model->aabb[0][1] = -1.0f;
model->aabb[0][2] = -1.0f;
model->aabb[1][0] = 1.0f;
model->aabb[1][1] = 1.0f;
model->aabb[1][2] = 1.0f;
model->nr_materials = 1;
model->materials = xcalloc(1, sizeof(struct material));
struct material *material = &model->materials[0];
material->is_transparent = true;
glGenTextures(1, &material->color_map);
glBindTexture(GL_TEXTURE_2D, material->color_map);
uint8_t pixel[4] = {r, g, b, a};
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
glBindTexture(GL_TEXTURE_2D, 0);
model->has_transparent_material = true;
return model;
}
static int cmp_motions_by_bone_id(const void *lhs, const void *rhs)
{
return (*(struct mot_bone **)lhs)->id - (*(struct mot_bone **)rhs)->id;
}
static struct mot *mot_load(const char *name, struct model *model, struct archive *aar)
{
struct archive_data *dfile = RE_get_aar_entry(aar, model->path, name, ".MOT");
if (!dfile) {
WARNING("%s\\%s.MOT: not found", model->path, name);
return NULL;
}
struct mot *mot = mot_parse(dfile->data, dfile->size, name);
if (!mot) {
WARNING("%s: parse error", dfile->name);
archive_free_data(dfile);
return NULL;
}
archive_free_data(dfile);
if (model->nr_bones != (int)mot->nr_bones)
ERROR("%s: wrong number of bones. Expected %d but got %d", name, model->nr_bones, mot->nr_bones);
// Reorder mot->motions so that motion for model->bones[i] can be
// accessed by mot->motions[i].
for (uint32_t i = 0; i < mot->nr_bones; i++) {
// Match by name first, since some MOT have wrong bone IDs (e.g. maidsan_ahoge_*).
struct bone *bone = ht_get(model->bone_name_map, mot->motions[i]->name, NULL);
// If it is not found or is NULL (non-unique bone name), match by bone ID.
if (!bone)
bone = ht_get_int(model->bone_map, mot->motions[i]->id, NULL);
if (!bone)
ERROR("%s: invalid bone \"%s\" (%d)", name, mot->motions[i]->name, mot->motions[i]->id);
mot->motions[i]->id = bone->index;
}
qsort(mot->motions, mot->nr_bones, sizeof(struct mot_bone *), cmp_motions_by_bone_id);
return mot;
}
struct motion *motion_load(const char *name, struct RE_instance *instance, struct archive *aar)
{
struct model *model = instance->model;
if (!model || !model->mot_cache)
return NULL;
struct mot *mot = ht_get(model->mot_cache, name, NULL);
if (!mot) {
mot = mot_load(name, model, aar);
if (!mot)
return NULL;
ht_put(model->mot_cache, name, mot);
}
struct motion *motion = xcalloc(1, sizeof(struct motion));
motion->instance = instance;
motion->mot = mot;
return motion;
}
void motion_free(struct motion *motion)
{
free(motion);
}
+459
View File
@@ -0,0 +1,459 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <cglm/cglm.h>
#include "system4.h"
#include "system4/buffer.h"
#include "3d_internal.h"
#define METERS_PER_INCH 0.0254
static char *read_cstring(struct buffer *r)
{
char *s = strdup(buffer_strdata(r));
buffer_skip(r, strlen(s) + 1);
return s;
}
static void read_position(struct buffer *r, vec3 v)
{
// left->right handed system
v[0] = buffer_read_float(r) * METERS_PER_INCH;
v[1] = buffer_read_float(r) * METERS_PER_INCH;
v[2] = -buffer_read_float(r) * METERS_PER_INCH;
}
static void read_direction(struct buffer *r, vec3 v)
{
// left->right handed system
v[0] = buffer_read_float(r);
v[1] = buffer_read_float(r);
v[2] = -buffer_read_float(r);
}
static void read_quaternion(struct buffer *r, versor q)
{
// left->right handed system
float w = buffer_read_float(r);
float x = -buffer_read_float(r);
float y = -buffer_read_float(r);
float z = buffer_read_float(r);
glm_quat_init(q, x, y, z, w);
glm_quat_normalize(q);
}
static uint32_t parse_material_attributes(const char *name)
{
uint32_t flags = 0;
if (strstr(name, "(sprite)"))
flags |= MATERIAL_SPRITE;
return flags;
}
static void parse_material(struct buffer *r, struct pol_material *m)
{
m->name = read_cstring(r);
m->flags = parse_material_attributes(m->name);
int nr_textures = buffer_read_int32(r);
for (int i = 0; i < nr_textures; i++) {
char *filename = read_cstring(r);
int type = buffer_read_int32(r);
if ((unsigned)type < MAX_TEXTURE_TYPE) {
m->textures[type] = filename;
} else {
WARNING("invalid texture type %d", type);
free(filename);
}
}
}
static void destroy_material(struct pol_material *m)
{
free(m->name);
for (int i = 0; i < MAX_TEXTURE_TYPE; i++)
free(m->textures[i]);
}
static void parse_material_group(struct buffer *r, struct pol_material_group *mg)
{
parse_material(r, &mg->m);
mg->nr_children = buffer_read_int32(r);
if (mg->nr_children > 0) {
mg->children = xcalloc(mg->nr_children, sizeof(struct pol_material));
for (uint32_t i = 0; i < mg->nr_children; i++) {
parse_material(r, &mg->children[i]);
}
}
}
static void destroy_material_group(struct pol_material_group *mg)
{
destroy_material(&mg->m);
if (mg->children) {
for (uint32_t i = 0; i < mg->nr_children; i++)
destroy_material(&mg->children[i]);
free(mg->children);
}
}
static void parse_vertex(struct buffer *r, int pol_version, struct pol_vertex *v)
{
read_position(r, v->pos);
v->nr_weights = pol_version == 1 ? buffer_read_int32(r) : buffer_read_u16(r);
if (v->nr_weights) {
v->weights = xcalloc(v->nr_weights, sizeof(struct pol_bone_weight));
for (uint32_t i = 0; i < v->nr_weights; i++) {
v->weights[i].bone = pol_version == 1 ? buffer_read_int32(r) : buffer_read_u16(r);
v->weights[i].weight = buffer_read_float(r);
}
}
}
static void destroy_vertex(struct pol_vertex *v)
{
if (v->weights)
free(v->weights);
}
static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle_index, int unknowns_length, const struct pol_material_group *mg)
{
struct pol_triangle *t = &mesh->triangles[triangle_index];
t->vert_index[0] = buffer_read_int32(r);
t->vert_index[1] = buffer_read_int32(r);
t->vert_index[2] = buffer_read_int32(r);
t->uv_index[0] = buffer_read_int32(r);
t->uv_index[1] = buffer_read_int32(r);
t->uv_index[2] = buffer_read_int32(r);
if (mesh->light_uvs) {
t->light_uv_index[0] = buffer_read_int32(r) - mesh->nr_uvs;
t->light_uv_index[1] = buffer_read_int32(r) - mesh->nr_uvs;
t->light_uv_index[2] = buffer_read_int32(r) - mesh->nr_uvs;
}
buffer_skip(r, unknowns_length);
read_direction(r, t->normals[0]);
read_direction(r, t->normals[1]);
read_direction(r, t->normals[2]);
t->material_group_index = buffer_read_int32(r);
if (t->material_group_index >= mg->nr_children)
t->material_group_index = 0;
}
static uint32_t parse_mesh_attributes(const char *name)
{
uint32_t flags = 0;
if (strstr(name, "(nolighting)"))
flags |= MESH_NOLIGHTING;
if (strstr(name, "(nomakeshadow)"))
flags |= MESH_NOMAKESHADOW;
if (strstr(name, "(env)"))
flags |= MESH_ENVMAP;
if (strstr(name, "(both)"))
flags |= MESH_BOTH;
if (strstr(name, "(sprite)"))
flags |= MESH_SPRITE;
return flags;
}
static struct pol_mesh *parse_mesh(struct buffer *r, const struct pol *pol)
{
int type = buffer_read_int32(r);
if (type != 0) {
if (type != -1)
WARNING("unknown mesh type: %d", type);
return NULL;
}
struct pol_mesh *mesh = xcalloc(1, sizeof(struct pol_mesh));
mesh->name = read_cstring(r);
mesh->flags = parse_mesh_attributes(mesh->name);
mesh->material = buffer_read_int32(r);
if (mesh->material >= pol->nr_materials) {
WARNING("material index out of range (%d >= %d)", mesh->material, pol->nr_materials);
mesh->material = 0;
}
mesh->nr_vertices = buffer_read_int32(r);
mesh->vertices = xcalloc(mesh->nr_vertices, sizeof(struct pol_vertex));
for (uint32_t i = 0; i < mesh->nr_vertices; i++) {
parse_vertex(r, pol->version, &mesh->vertices[i]);
}
mesh->nr_uvs = buffer_read_int32(r);
mesh->uvs = xcalloc(mesh->nr_uvs, sizeof(vec2));
for (uint32_t i = 0; i < mesh->nr_uvs; i++) {
mesh->uvs[i][0] = buffer_read_float(r);
mesh->uvs[i][1] = buffer_read_float(r);
}
mesh->nr_light_uvs = buffer_read_int32(r);
if (mesh->nr_light_uvs > 0) {
mesh->light_uvs = xcalloc(mesh->nr_light_uvs, sizeof(vec2));
for (uint32_t i = 0; i < mesh->nr_light_uvs; i++) {
mesh->light_uvs[i][0] = buffer_read_float(r);
mesh->light_uvs[i][1] = buffer_read_float(r);
}
}
int triangle_unknowns_length = 12;
if (pol->version == 1) {
int nr_unknown_vecs = buffer_read_int32(r);
buffer_skip(r, nr_unknown_vecs * 12);
} else {
int nr_unknown_ints = buffer_read_int32(r);
buffer_skip(r, nr_unknown_ints * 4);
int nr_unknown_bytes = buffer_read_int32(r);
if (nr_unknown_bytes) {
buffer_skip(r, nr_unknown_bytes);
triangle_unknowns_length += 12;
}
}
mesh->nr_triangles = buffer_read_int32(r);
mesh->triangles = xcalloc(mesh->nr_triangles, sizeof(struct pol_triangle));
for (uint32_t i = 0; i < mesh->nr_triangles; i++) {
parse_triangle(r, mesh, i, triangle_unknowns_length, &pol->materials[mesh->material]);
}
if (pol->version == 1) {
if (buffer_read_int32(r) != 1)
WARNING("unexpected mesh footer");
if (buffer_read_int32(r) != 0)
WARNING("unexpected mesh footer");
}
return mesh;
}
static void free_mesh(struct pol_mesh *mesh)
{
if (!mesh)
return;
free(mesh->name);
for (uint32_t i = 0; i < mesh->nr_vertices; i++)
destroy_vertex(&mesh->vertices[i]);
free(mesh->vertices);
free(mesh->uvs);
free(mesh->light_uvs);
free(mesh->triangles);
free(mesh);
}
static void parse_bone(struct buffer *r, struct pol_bone *bone)
{
bone->name = read_cstring(r);
bone->id = buffer_read_int32(r);
bone->parent = buffer_read_int32(r);
read_position(r, bone->pos);
read_quaternion(r, bone->rotq);
}
static void destroy_bone(struct pol_bone *bone)
{
free(bone->name);
}
struct pol *pol_parse(uint8_t *data, size_t size)
{
struct buffer r;
buffer_init(&r, data, size);
if (memcmp(buffer_strdata(&r), "POL\0", 4))
return NULL;
buffer_skip(&r, 4);
struct pol *pol = xcalloc(1, sizeof(struct pol));
pol->version = buffer_read_int32(&r);
if (pol->version != 1 && pol->version != 2) {
WARNING("unknown POL version: %d", pol->version);
free(pol);
return NULL;
}
pol->nr_materials = buffer_read_int32(&r);
pol->materials = xcalloc(pol->nr_materials, sizeof(struct pol_material_group));
for (uint32_t i = 0; i < pol->nr_materials; i++) {
parse_material_group(&r, &pol->materials[i]);
}
pol->nr_meshes = buffer_read_int32(&r);
pol->meshes = xcalloc(pol->nr_meshes, sizeof(struct pol_mesh *));
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
pol->meshes[i] = parse_mesh(&r, pol);
}
pol->nr_bones = buffer_read_int32(&r);
if (pol->nr_bones) {
pol->bones = xcalloc(pol->nr_bones, sizeof(struct pol_bone));
for (uint32_t i = 0; i < pol->nr_bones; i++) {
parse_bone(&r, &pol->bones[i]);
}
}
if (buffer_remaining(&r) != 0) {
WARNING("extra data at end");
}
return pol;
}
void pol_free(struct pol *pol)
{
for (uint32_t i = 0; i < pol->nr_materials; i++)
destroy_material_group(&pol->materials[i]);
free(pol->materials);
for (uint32_t i = 0; i < pol->nr_meshes; i++)
free_mesh(pol->meshes[i]);
free(pol->meshes);
for (uint32_t i = 0; i < pol->nr_bones; i++)
destroy_bone(&pol->bones[i]);
free(pol->bones);
free(pol);
}
void pol_compute_aabb(struct pol *pol, vec3 dest[2])
{
vec3 aabb[2];
glm_aabb_invalidate(aabb);
for (uint32_t i = 0; i < pol->nr_meshes; i++) {
struct pol_mesh *mesh = pol->meshes[i];
if (!mesh)
continue;
for (uint32_t j = 0; j < mesh->nr_vertices; j++) {
glm_vec3_minv(mesh->vertices[j].pos, aabb[0], aabb[0]);
glm_vec3_maxv(mesh->vertices[j].pos, aabb[1], aabb[1]);
}
}
glm_vec3_copy(aabb[0], dest[0]);
glm_vec3_copy(aabb[1], dest[1]);
}
struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id)
{
for (uint32_t i = 0; i < pol->nr_bones; i++) {
if (pol->bones[i].id == id)
return &pol->bones[i];
}
return NULL;
}
struct mot *mot_parse(uint8_t *data, size_t size, const char *name)
{
struct buffer r;
buffer_init(&r, data, size);
if (memcmp(buffer_strdata(&r), "MOT\0", 4))
return NULL;
buffer_skip(&r, 4);
uint32_t version = buffer_read_int32(&r);
if (version != 0) {
WARNING("unknown MOT version: %d", version);
return NULL;
}
uint32_t nr_frames = buffer_read_int32(&r);
uint32_t nr_bones = buffer_read_int32(&r);
struct mot *mot = xcalloc(1, sizeof(struct mot) + nr_bones * sizeof(struct mot_bone *));
mot->name = strdup(name);
mot->nr_frames = nr_frames;
mot->nr_bones = nr_bones;
for (uint32_t i = 0; i < nr_bones; i++) {
struct mot_bone *m = xcalloc(1, sizeof(struct mot_bone) + sizeof(struct mot_frame) * nr_frames);
m->name = read_cstring(&r);
m->id = buffer_read_int32(&r);
m->parent = buffer_read_int32(&r);
for (uint32_t j = 0; j < nr_frames; j++) {
read_position(&r, m->frames[j].pos);
read_quaternion(&r, m->frames[j].rotq);
buffer_skip(&r, 16); // another quaternion?
}
mot->motions[i] = m;
}
if (buffer_remaining(&r) != 0) {
WARNING("extra data at end");
}
return mot;
}
void mot_free(struct mot *mot)
{
free(mot->name);
for (uint32_t i = 0; i < mot->nr_bones; i++) {
free(mot->motions[i]->name);
free(mot->motions[i]);
}
free(mot);
}
struct amt *amt_parse(uint8_t *data, size_t size)
{
struct buffer r;
buffer_init(&r, data, size);
if (memcmp(buffer_strdata(&r), "AMT\0", 4))
return NULL;
buffer_skip(&r, 4);
uint32_t version = buffer_read_int32(&r);
int nr_fields;
switch (version) {
case 1: nr_fields = 3; break;
case 2: nr_fields = 5; break;
case 3: nr_fields = 6; break;
case 4: nr_fields = 7; break;
case 5: nr_fields = 11; break;
case 6: nr_fields = 15; break;
default:
WARNING("unknown MOT version: %d", version);
return NULL;
}
int nr_materials = buffer_read_int32(&r);
struct amt *amt = xmalloc(sizeof(struct amt) + sizeof(struct amt_material *) * nr_materials);
amt->version = version;
amt->nr_materials = nr_materials;
for (int i = 0; i < nr_materials; i++) {
struct amt_material *m = amt->materials[i] =
xmalloc(sizeof(struct amt_material) + sizeof(float) * nr_fields);
m->name = read_cstring(&r);
for (int j = 0; j < nr_fields; j++)
m->fields[j] = buffer_read_float(&r);
}
if (buffer_remaining(&r) != 0) {
WARNING("extra data at end");
}
return amt;
}
void amt_free(struct amt *amt)
{
for (int i = 0; i < amt->nr_materials; i++) {
free(amt->materials[i]->name);
free(amt->materials[i]);
}
free(amt);
}
struct amt_material *amt_find_material(struct amt *amt, const char *name)
{
for (int i = 0; i < amt->nr_materials; i++) {
if (!strcmp(amt->materials[i]->name, name))
return amt->materials[i];
}
return NULL;
}
+995
View File
@@ -0,0 +1,995 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <limits.h>
#include <cglm/cglm.h>
#include "system4.h"
#include "system4/aar.h"
#include "system4/cg.h"
#include "system4/hashtable.h"
#include "system4/utfsjis.h"
#include "3d_internal.h"
static inline float randf(void)
{
return rand() / (float)RAND_MAX;
}
static void parse_error(const char *msg, char *input)
{
char *eol = strchr(input, '\n');
*eol = '\0';
WARNING("Parse error: %s Near: \"%s\"", msg, input);
}
static enum particle_type parse_particle_type(const char *s)
{
if (!strcmp(s, "ビルボード"))
return PARTICLE_TYPE_BILLBOARD;
else if (!strcmp(s, "ポリゴンオブジェクト"))
return PARTICLE_TYPE_POLYGON_OBJECT;
else if (!strcmp(s, "剣ブラー"))
return PARTICLE_TYPE_SWORD_BLUR;
else if (!strcmp(s, "カメラ振動"))
return PARTICLE_TYPE_CAMERA_QUAKE;
WARNING("unknown object type \"%s\"", s);
return (enum particle_type)-1;
}
static enum particle_move_type parse_particle_move_type(const char *s)
{
if (!strcmp(s, "固定"))
return PARTICLE_MOVE_FIXED;
else if (!strcmp(s, "直線"))
return PARTICLE_MOVE_LINEAR;
else if (!strcmp(s, "放射"))
return PARTICLE_MOVE_EMITTER;
WARNING("unknown move type \"%s\"", s);
return (enum particle_move_type)-1;
}
static enum particle_blend_type parse_particle_blend_type(const char *s)
{
if (!strcmp(s, "標準"))
return PARTICLE_BLEND_NORMAL;
else if (!strcmp(s, "加算"))
return PARTICLE_BLEND_ADDITIVE;
WARNING("unknown blend type \"%s\"", s);
return (enum particle_blend_type)-1;
}
static enum particle_frame_ref_type parse_particle_frame_ref_type(const char *s, int *param)
{
if (!strcmp(s, "エフェクト"))
return PARTICLE_FRAME_REF_EFFECT;
else if (sscanf(s, "ターゲット[%d]", param) == 1)
return PARTICLE_FRAME_REF_TARGET;
WARNING("unknown frame ref type \"%s\"", s);
return (enum particle_frame_ref_type)-1;
}
static char *parse_quoted_string(char **ptext)
{
char *text = *ptext;
if (*text++ != '"') {
parse_error("quoted string expected.", text);
return NULL;
}
char *p = strchr(text, '"');
if (!p) {
parse_error("unfinished string.", text);
return NULL;
}
*p = '\0';
*ptext = p + 1;
return utf2sjis(text, 0);
}
#define MATCH(fmt, ...) (len = 0, sscanf(text, fmt " %n", ##__VA_ARGS__, &len), text += len, len)
#define STRING_BUF_SIZE 64
#define KEYWORD "%63s"
#define QUOTED_STRING "\"%63[^\"]\""
static float *parse_float_list(char **ptext, int *nr)
{
char *text = *ptext;
int len;
float f;
if (!MATCH("%f", &f)) {
parse_error("float expected.", text);
return NULL;
}
int cap = 16;
float *floats = xmalloc(cap * sizeof(float));
floats[0] = f;
*nr = 1;
while (MATCH(" , %f", &f)) {
if (*nr == cap) {
cap *= 2;
floats = xrealloc(floats, cap * sizeof(float));
}
floats[(*nr)++] = f;
}
*ptext = text;
return floats;
}
static int *parse_int_list(char **ptext, int *nr)
{
char *text = *ptext;
int len;
int n;
if (!MATCH("%d", &n)) {
parse_error("int expected.", text);
return NULL;
}
int cap = 16;
int *ints = xmalloc(cap * sizeof(int));
ints[0] = n;
*nr = 1;
while (MATCH(" , %d", &n)) {
if (*nr == cap) {
cap *= 2;
ints = xrealloc(ints, cap * sizeof(int));
}
ints[(*nr)++] = n;
}
*ptext = text;
return ints;
}
static char **parse_qstr_list(char **ptext, int *nr, bool ignore_empty)
{
char *text = *ptext;
int len;
int cap = 16;
char **strs = xmalloc(cap * sizeof(char *));
*nr = 0;
do {
if (*nr == cap) {
cap *= 2;
strs = xrealloc(strs, cap * sizeof(char *));
}
char *s = parse_quoted_string(&text);
if (!s) {
for (int i = 0; i < *nr; i++)
free(strs[i]);
free(strs);
return NULL;
}
if (s[0] == '\0' && ignore_empty)
free(s);
else
strs[(*nr)++] = s;
} while (MATCH(" , "));
*ptext = text;
return strs;
}
static struct particle_position *parse_position(char **ptext)
{
char *text = *ptext;
int len;
struct particle_position *epos = xcalloc(1, sizeof(struct particle_position));
int n;
float x, y, z;
char string_buf[STRING_BUF_SIZE];
for (int i = 0; i < NR_PARTICLE_POSITION_UNITS; i++) {
struct particle_position_unit *unit = &epos->units[i];
if (MATCH("なし")) {
unit->type = PARTICLE_POS_UNIT_NONE;
} else if (MATCH("絶対位置( %f , %f , %f )", &x, &y, &z)) {
unit->type = PARTICLE_POS_UNIT_ABSOLUTE;
unit->absolute[0] = x;
unit->absolute[1] = y;
unit->absolute[2] = -z;
} else if (MATCH("ボーン[ %d , "QUOTED_STRING" , %f , %f , %f ]", &n, string_buf, &x, &y, &z) ||
MATCH("ボーン[ %d , \"\" , %f , %f , %f ]", &n, &x, &y, &z)) {
unit->type = PARTICLE_POS_UNIT_BONE;
unit->bone.target_index = n;
unit->bone.name = utf2sjis(string_buf, 0);
unit->bone.offset[0] = x;
unit->bone.offset[1] = y;
unit->bone.offset[2] = -z;
} else if (MATCH("ターゲット[ %d , %f , %f , %f ]", &n, &x, &y, &z)) {
unit->type = PARTICLE_POS_UNIT_TARGET;
unit->target.index = n;
unit->target.offset[0] = x;
unit->target.offset[1] = y;
unit->target.offset[2] = -z;
} else if (MATCH("ランダム方向( %f )", &x)) {
unit->type = PARTICLE_POS_UNIT_RAND;
unit->rand.f = x;
} else if (MATCH("ランダム方向Y+( %f )", &x)) {
unit->type = PARTICLE_POS_UNIT_RAND_POSITIVE_Y;
unit->rand.f = x;
} else {
parse_error("unknown position unit.", text);
free(epos);
return NULL;
}
if (!MATCH(" + "))
break;
}
*ptext = text;
return epos;
}
static struct pae *parse_pae(char *text)
{
struct pae *pae = xcalloc(1, sizeof(struct pae));
struct pae_object *current_object = NULL;
for (;;) {
// Skip whitespaces and comments
for (;;) {
while (isspace(*text))
text++;
if (text[0] == '/' && text[1] == '/') {
char *newline = strchr(text, '\n');
if (newline)
text = newline + 1;
else
text += strlen(text);
} else {
break;
}
}
int len;
int n, n2;
float f, f2;
char string_buf[STRING_BUF_SIZE];
if (!current_object) {
// Toplevel
if (!*text) { // EOF
return pae;
} else if (MATCH("オブジェクト " QUOTED_STRING " = {", string_buf)) {
pae->objects = xrealloc_array(pae->objects, pae->nr_objects, pae->nr_objects + 1, sizeof(struct pae_object));
current_object = &pae->objects[pae->nr_objects++];
current_object->name = utf2sjis(string_buf, 0);
// Default values.
current_object->move_type = PARTICLE_MOVE_LINEAR;
current_object->texture_anime_frame = 1.0;
current_object->child_end_slope = 1.0;
} else {
parse_error("unknown toplevel.", text);
goto err;
}
} else {
// Object context
if (!*text) {
WARNING("unexpected EOF");
return false;
} else if (MATCH("}")) {
current_object = NULL;
} else if (MATCH("種類 = " KEYWORD, string_buf)) {
current_object->type = parse_particle_type(string_buf);
if (current_object->type < 0)
goto err;
} else if (MATCH("移動タイプ = " KEYWORD, string_buf)) {
current_object->move_type = parse_particle_move_type(string_buf);
if (current_object->move_type < 0)
goto err;
} else if (MATCH("アップベクトルタイプ = %d", &n)) {
if (n > PARTICLE_UP_VECTOR_TYPE_MAX) {
WARNING("unknown up vector type %d", n);
n = PARTICLE_UP_VECTOR_TYPE_MAX;
}
current_object->up_vector_type = n;
} else if (MATCH("移動カーブ = %f", &f)) {
current_object->move_curve = f;
} else if (MATCH("位置 = ")) {
current_object->position[0] = parse_position(&text);
if (!current_object->position[0])
goto err;
if (MATCH(" , ")) {
current_object->position[1] = parse_position(&text);
if (!current_object->position[1])
goto err;
}
} else if (MATCH("サイズ = %f", &f)) {
current_object->size[0] = f;
if (MATCH(" , %f", &f2))
current_object->size[1] = f2;
else
current_object->size[1] = f;
} else if (MATCH("サイズ2 = ")) {
current_object->sizes2 = parse_float_list(&text, &current_object->nr_sizes2);
if (!current_object->sizes2)
goto err;
} else if (MATCH("サイズX = ")) {
current_object->sizes_x = parse_float_list(&text, &current_object->nr_sizes_x);
if (!current_object->sizes_x)
goto err;
} else if (MATCH("サイズY = ")) {
current_object->sizes_y = parse_float_list(&text, &current_object->nr_sizes_y);
if (!current_object->sizes_y)
goto err;
} else if (MATCH("サイズタイプ = ")) {
current_object->size_types = parse_int_list(&text, &current_object->nr_size_types);
if (!current_object->size_types)
goto err;
} else if (MATCH("サイズXタイプ = ")) {
current_object->size_x_types = parse_int_list(&text, &current_object->nr_size_x_types);
if (!current_object->size_x_types)
goto err;
} else if (MATCH("サイズYタイプ = ")) {
current_object->size_y_types = parse_int_list(&text, &current_object->nr_size_y_types);
if (!current_object->size_y_types)
goto err;
} else if (MATCH("テクスチャ = ")) {
current_object->textures = parse_qstr_list(&text, &current_object->nr_textures, true);
if (!current_object->textures)
goto err;
} else if (MATCH("ブレンドタイプ = " KEYWORD, string_buf)) {
current_object->blend_type = parse_particle_blend_type(string_buf);
if (current_object->blend_type < 0)
goto err;
} else if (MATCH("テクスチャアニメフレーム = %f", &f)) {
current_object->texture_anime_frame = f;
} else if (MATCH("テクスチャアニメ時間 = %d", &n)) {
current_object->texture_anime_time = n;
} else if (MATCH("ポリゴン = ")) {
current_object->polygon_name = parse_quoted_string(&text);
if (!current_object->polygon_name)
goto err;
} else if (MATCH("フレーム = %d , %d", &n, &n2)) {
current_object->begin_frame = n;
current_object->end_frame = n2;
} else if (MATCH("停止フレーム = %d", &n)) {
current_object->stop_frame = n;
} else if (MATCH("フレーム参照 = " KEYWORD, string_buf)) {
current_object->frame_ref_type = parse_particle_frame_ref_type(string_buf, &current_object->frame_ref_param);
if (current_object->frame_ref_type < 0)
goto err;
} else if (MATCH("個数 = %d", &n)) {
current_object->nr_particles = n;
} else if (MATCH("アルファフェードインフレーム = %f", &f)) {
current_object->alpha_fadein_frame = f;
} else if (MATCH("アルファフェードイン時間 = %d", &n)) {
current_object->alpha_fadein_time = n;
} else if (MATCH("アルファフェードアウトフレーム = %f", &f)) {
current_object->alpha_fadeout_frame = f;
} else if (MATCH("アルファフェードアウト時間 = %d", &n)) {
current_object->alpha_fadeout_time = n;
} else if (MATCH("X軸自転角度 = %f , %f", &f, &f2)) {
current_object->rotation.begin[0] = f;
current_object->rotation.end[0] = f2;
} else if (MATCH("Y軸自転角度 = %f , %f", &f, &f2)) {
current_object->rotation.begin[1] = f;
current_object->rotation.end[1] = f2;
} else if (MATCH("Z軸自転角度 = %f , %f", &f, &f2)) {
current_object->rotation.begin[2] = f;
current_object->rotation.end[2] = f2;
} else if (MATCH("X軸公転角度 = %f , %f", &f, &f2)) {
current_object->revolution_angle.begin[0] = f;
current_object->revolution_angle.end[0] = f2;
} else if (MATCH("Y軸公転角度 = %f , %f", &f, &f2)) {
current_object->revolution_angle.begin[1] = f;
current_object->revolution_angle.end[1] = f2;
} else if (MATCH("Z軸公転角度 = %f , %f", &f, &f2)) {
current_object->revolution_angle.begin[2] = f;
current_object->revolution_angle.end[2] = f2;
} else if (MATCH("X軸公転距離 = %f , %f", &f, &f2)) {
current_object->revolution_distance.begin[0] = f;
current_object->revolution_distance.end[0] = f2;
} else if (MATCH("Y軸公転距離 = %f , %f", &f, &f2)) {
current_object->revolution_distance.begin[1] = f;
current_object->revolution_distance.end[1] = f2;
} else if (MATCH("Z軸公転距離 = %f , %f", &f, &f2)) {
current_object->revolution_distance.begin[2] = f;
current_object->revolution_distance.end[2] = f2;
} else if (MATCH("カーブX距離 = %f", &f)) {
current_object->curve_length[0] = f;
} else if (MATCH("カーブY距離 = %f", &f)) {
current_object->curve_length[1] = f;
} else if (MATCH("カーブZ距離 = %f", &f)) {
current_object->curve_length[2] = -f;
} else if (MATCH("子フレーム = %d", &n)) {
current_object->child_frame = n;
} else if (MATCH("子距離 = %f", &f)) {
current_object->child_length = f;
} else if (MATCH("子傾き = %f", &f)) {
current_object->child_begin_slope = f;
} else if (MATCH("子傾き2 = %f", &f)) {
current_object->child_end_slope = f;
} else if (MATCH("子生成開始フレーム = %f", &f)) {
current_object->child_create_begin_frame = f;
} else if (MATCH("子生成終了フレーム = %f", &f)) {
current_object->child_create_end_frame = f;
} else if (MATCH("子移動方向タイプ = %d", &n)) {
if (n > PARTICLE_CHILD_MOVE_DIR_TYPE_MAX) {
WARNING("unknown child move dir type %d", n);
n = PARTICLE_CHILD_MOVE_DIR_TYPE_MAX;
}
current_object->child_move_dir_type = n;
} else if (MATCH("方向タイプ = %d", &n)) {
if (n > PARTICLE_DIR_TYPE_MAX) {
WARNING("unknown dir type %d", n);
n = PARTICLE_DIR_TYPE_MAX;
}
current_object->dir_type = n;
} else if (MATCH("ダメージ = ")) {
current_object->damages = parse_int_list(&text, &current_object->nr_damages);
if (!current_object->damages)
goto err;
} else if (MATCH("オフセットX = %f", &f)) {
current_object->offset_x = f;
} else if (MATCH("オフセットY = %f", &f)) {
current_object->offset_y = f;
} else {
parse_error("unknown object field.", text);
goto err;
}
}
}
err:
pae_free(pae);
return NULL;
}
static void load_textures(struct pae *effect, struct archive *aar)
{
effect->textures = ht_create(16);
for (int i = 0; i < effect->nr_objects; i++) {
struct pae_object *po = &effect->objects[i];
for (int j = 0; j < po->nr_textures; j++) {
const char *name = po->textures[j];
if (ht_get(effect->textures, name, NULL))
continue; // already loaded.
struct archive_data *dfile = RE_get_aar_entry(aar, effect->path, name, ".bmp");
if (!dfile)
dfile = RE_get_aar_entry(aar, effect->path, name, ".tga");
if (!dfile) {
WARNING("cannot load texture %s\\%s", effect->path, name);
continue;
}
struct cg *cg = cg_load_data(dfile);
if (!cg) {
WARNING("cg_load_data failed: %s", dfile->name);
archive_free_data(dfile);
continue;
}
archive_free_data(dfile);
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
struct billboard_texture *bt = xcalloc(1, sizeof(struct billboard_texture));
bt->texture = texture;
bt->has_alpha = cg->metrics.has_alpha;
ht_put(effect->textures, name, bt);
cg_free(cg);
}
}
}
static struct RE_instance *get_target(struct RE_instance *inst, int index)
{
int target_id = inst->target[index];
if (target_id < 0 || target_id >= inst->plugin->nr_instances)
return NULL;
return inst->plugin->instances[target_id];
}
static void eval_pos_for_object(struct RE_instance *inst, struct particle_position *pp, vec3 dest)
{
glm_vec3_zero(dest);
if (!pp)
return;
for (int i = 0; i < NR_PARTICLE_POSITION_UNITS; i++) {
struct particle_position_unit *unit = &pp->units[i];
switch (unit->type) {
case PARTICLE_POS_UNIT_NONE:
break;
case PARTICLE_POS_UNIT_RAND:
case PARTICLE_POS_UNIT_RAND_POSITIVE_Y:
// These are computed per instance, in eval_pos_for_instance().
break;
case PARTICLE_POS_UNIT_ABSOLUTE:
glm_vec3_add(dest, unit->absolute, dest);
break;
case PARTICLE_POS_UNIT_BONE:
{
struct RE_instance *target = get_target(inst, unit->bone.target_index);
int bone = RE_instance_get_bone_index(target, unit->bone.name);
vec3 target_pos;
if (RE_instance_trans_local_pos_to_world_pos_by_bone(target, bone, unit->bone.offset, target_pos))
glm_vec3_add(dest, target_pos, dest);
else
glm_vec3_add(dest, unit->bone.offset, dest);
}
break;
case PARTICLE_POS_UNIT_TARGET:
{
struct RE_instance *target = get_target(inst, unit->target.index);
if (!target)
break;
vec3 scale = {
target->column_radius,
target->column_height,
target->column_radius
};
mat4 transform;
glm_scale_make(transform, scale);
glm_rotate_y(transform, -glm_rad(target->column_angle), transform);
vec3 target_pos;
glm_mat4_mulv3(transform, unit->target.offset, 1.0f, target_pos);
glm_vec3_addadd(target->pos, target->column_pos, target_pos);
glm_vec3_add(dest, target_pos, dest);
}
break;
}
}
}
static void eval_pos_for_instance(struct particle_position *pp, vec3 dest)
{
glm_vec3_zero(dest);
if (!pp)
return;
for (int i = 0; i < NR_PARTICLE_POSITION_UNITS; i++) {
struct particle_position_unit *unit = &pp->units[i];
switch (unit->type) {
case PARTICLE_POS_UNIT_NONE:
break;
case PARTICLE_POS_UNIT_ABSOLUTE:
case PARTICLE_POS_UNIT_BONE:
case PARTICLE_POS_UNIT_TARGET:
// These are computed per object, in eval_pos_for_object().
break;
case PARTICLE_POS_UNIT_RAND:
dest[0] += (randf() * 2.0 - 1.0) * unit->rand.f;
dest[1] += (randf() * 2.0 - 1.0) * unit->rand.f;
dest[2] += (randf() * 2.0 - 1.0) * unit->rand.f;
break;
case PARTICLE_POS_UNIT_RAND_POSITIVE_Y:
dest[0] += (randf() * 2.0 - 1.0) * unit->rand.f;
dest[1] += randf() * unit->rand.f;
dest[2] += (randf() * 2.0 - 1.0) * unit->rand.f;
break;
}
}
}
static float eval_child_slope(struct pae_object *po)
{
float slope = glm_lerp(po->child_begin_slope, po->child_end_slope, randf());
if (slope > 1.0)
slope = 0.5 + 0.5 / slope; // ???
return (1.0 + slope) * GLM_PI_2;
}
static void interpolate_pos(vec3 begin, vec3 end, float move_curve, float t, vec3 dest)
{
if (move_curve == 0.0f) {
glm_vec3_copy(end, dest);
return;
}
float x = move_curve > 0.0f ? powf(t, move_curve) : 1.0f - powf(1.0f - t, -move_curve);
glm_vec3_lerp(begin, end, x, dest);
}
static void init_particle_instances(struct particle_object *po)
{
struct pae_object *pae_obj = po->pae_obj;
po->instances = xcalloc(pae_obj->nr_particles, sizeof(struct particle_instance));
for (int i = 0; i < pae_obj->nr_particles; i++) {
struct particle_instance *pi = &po->instances[i];
switch (pae_obj->move_type) {
case PARTICLE_MOVE_FIXED:
case PARTICLE_MOVE_LINEAR:
pi->begin_frame = pae_obj->begin_frame;
pi->end_frame = pae_obj->end_frame;
break;
case PARTICLE_MOVE_EMITTER:
pi->begin_frame = glm_lerp(pae_obj->child_create_begin_frame, pae_obj->child_create_end_frame, (float)i / pae_obj->nr_particles);
pi->end_frame = pi->begin_frame + pae_obj->child_frame;
pi->roll_angle = eval_child_slope(pae_obj);
pi->pitch_angle = randf() * (2.0f * GLM_PIf);
break;
}
eval_pos_for_instance(pae_obj->position[0], pi->random_offset.begin);
eval_pos_for_instance(pae_obj->position[1], pi->random_offset.end);
}
}
struct pae *pae_load(struct archive *aar, const char *path)
{
const char *basename = strrchr(path, '\\');
basename = basename ? basename + 1 : path;
struct archive_data *dfile = RE_get_aar_entry(aar, path, basename, ".pae");
if (!dfile) {
WARNING("%s\\%s.pae: not found", path, basename);
return NULL;
}
char *sjis_text = xmalloc(dfile->size + 1);
memcpy(sjis_text, dfile->data, dfile->size);
// Replace null characters (written by buggy .pae formatter) with spaces.
for (size_t i = 0; i < dfile->size; i++) {
if (sjis_text[i] == '\0')
sjis_text[i] = ' ';
}
sjis_text[dfile->size] = '\0';
// We could parse the SJIS text directly, but convert it to UTF-8 for code
// clarity.
char *text = sjis2utf(sjis_text, dfile->size);
free(sjis_text);
struct pae *pae = parse_pae(text);
free(text);
if (!pae) {
WARNING("could not parse %s", dfile->name);
archive_free_data(dfile);
return NULL;
}
archive_free_data(dfile);
pae->path = strdup(path);
load_textures(pae, aar);
for (int i = 0; i < pae->nr_objects; i++) {
struct pae_object *po = &pae->objects[i];
if (po->polygon_name && *po->polygon_name) {
char *pol_path = xmalloc(strlen(path) + strlen(po->polygon_name) + 2);
sprintf(pol_path, "%s\\%s", path, po->polygon_name);
po->model = model_load(aar, pol_path);
free(pol_path);
}
}
return pae;
}
struct particle_effect *particle_effect_create(struct pae *pae)
{
struct particle_effect *effect = xcalloc(1, sizeof(struct particle_effect));
effect->pae = pae;
effect->objects = xcalloc(pae->nr_objects, sizeof(struct particle_object));
effect->camera_quake_enabled = true;
for (int i = 0; i < pae->nr_objects; i++) {
struct particle_object *po = &effect->objects[i];
po->pae_obj = &pae->objects[i];
init_particle_instances(po);
}
return effect;
}
static void free_billboard_texture(void *value)
{
struct billboard_texture *bt = value;
glDeleteTextures(1, &bt->texture);
free(bt);
}
static void particle_position_free(struct particle_position *pos)
{
if (!pos)
return;
for (int i = 0; i < NR_PARTICLE_POSITION_UNITS; i++) {
if (pos->units[i].type == PARTICLE_POS_UNIT_BONE)
free(pos->units[i].bone.name);
}
free(pos);
}
void pae_free(struct pae *pae)
{
for (int i = 0; i < pae->nr_objects; i++) {
struct pae_object *po = &pae->objects[i];
free(po->name);
for (int j = 0; j < NR_PARTICLE_POSITIONS; j++)
particle_position_free(po->position[j]);
free(po->sizes2);
free(po->sizes_x);
free(po->sizes_y);
free(po->size_types);
free(po->size_x_types);
free(po->size_y_types);
for (int j = 0; j < po->nr_textures; j++)
free(po->textures[j]);
free(po->textures);
free(po->polygon_name);
free(po->damages);
if (po->model)
model_free(po->model);
}
ht_foreach_value(pae->textures, free_billboard_texture);
ht_free(pae->textures);
free(pae->objects);
free(pae->path);
free(pae);
}
void particle_effect_free(struct particle_effect *effect)
{
for (int i = 0; i < effect->pae->nr_objects; i++) {
struct particle_object *obj = &effect->objects[i];
free(obj->instances);
}
free(effect->objects);
free(effect);
}
void pae_calc_frame_range(struct pae *pae, struct motion *motion)
{
int begin_frame = INT_MAX;
int end_frame = INT_MIN;
for (int i = 0; i < pae->nr_objects; i++) {
struct pae_object *po = &pae->objects[i];
int obj_begin = po->begin_frame;
int obj_end = max(po->end_frame, po->child_create_end_frame + po->child_frame);
if (begin_frame > obj_begin)
begin_frame = obj_begin;
if (end_frame < obj_end)
end_frame = obj_end;
}
motion->frame_begin = motion->loop_frame_begin = begin_frame;
motion->frame_end = motion->loop_frame_end = end_frame;
}
static void update_camera_quake(struct RE_instance *inst, struct pae_object *po)
{
float frame = inst->motion->current_frame - po->begin_frame;
float total_frames = po->end_frame - po->begin_frame;
if (frame < 0 || frame >= total_frames)
return;
const float ease_in_duration = 4.0f;
const float ease_out_duration = 4.0f;
float amplitude = 1.0f;
if (total_frames - frame < ease_out_duration)
amplitude *= (total_frames - frame) / ease_out_duration;
else if (frame < ease_in_duration)
amplitude *= frame / ease_in_duration;
inst->plugin->camera.quake_pitch = sinf(frame * 1.1) * amplitude * -8.0f;
inst->plugin->camera.quake_yaw = sinf(frame * 1.7) * amplitude * 12.0f;
}
void particle_effect_update(struct RE_instance *inst)
{
struct particle_effect *effect = inst->effect;
if (!effect)
return;
for (int i = 0; i < effect->pae->nr_objects; i++) {
struct particle_object *po = &effect->objects[i];
struct pae_object *pae_obj = po->pae_obj;
if (pae_obj->type == PARTICLE_TYPE_CAMERA_QUAKE) {
if (effect->camera_quake_enabled)
update_camera_quake(inst, pae_obj);
continue;
}
// These cannot be precomputed, because they may depend on the target's
// *current* bone matrix.
eval_pos_for_object(inst, pae_obj->position[0], po->pos.begin);
eval_pos_for_object(inst, pae_obj->position[1], po->pos.end);
glm_vec3_sub(po->pos.end, po->pos.begin, po->move_vec);
switch (pae_obj->dir_type) {
case PARTICLE_DIR_TYPE_NORMAL:
glm_vec3_normalize(po->move_vec);
glm_vec3_ortho(po->move_vec, po->move_ortho);
glm_vec3_normalize(po->move_ortho);
break;
case PARTICLE_DIR_TYPE_XY_PLANE:
po->move_vec[2] = 0.0f;
glm_vec3_normalize(po->move_vec);
glm_vec3_copy(GLM_ZUP, po->move_ortho);
break;
}
}
}
static void calc_emitter_pos(struct particle_object *po, struct particle_instance *pi, float t, vec3 dest, vec3 move_vec)
{
struct pae_object *pae_obj = po->pae_obj;
vec3 begin, end;
glm_vec3_add(po->pos.begin, pi->random_offset.begin, begin);
glm_vec3_add(po->pos.end, pi->random_offset.end, end);
interpolate_pos(begin, end, pae_obj->move_curve, t, dest);
if (move_vec)
glm_vec3_sub(end, begin, move_vec);
// Orbital rotation.
vec3 angle, dist;
glm_vec3_lerp(pae_obj->revolution_angle.begin, pae_obj->revolution_angle.end, t, angle);
glm_vec3_lerp(pae_obj->revolution_distance.begin, pae_obj->revolution_distance.end, t, dist);
glm_vec3_scale(angle, GLM_PIf / 180.0f, angle); // deg -> rad
if (pae_obj->revolution_angle.begin[0] != 0.0f || pae_obj->revolution_angle.end[0] != 0.0f) {
dest[1] += dist[0] * sinf(angle[0]);
dest[2] -= dist[0] * cosf(angle[0]);
}
if (pae_obj->revolution_angle.begin[1] != 0.0f || pae_obj->revolution_angle.end[1] != 0.0f) {
dest[0] += dist[1] * sinf(angle[1]);
dest[2] -= dist[1] * cosf(angle[1]);
}
if (pae_obj->revolution_angle.begin[2] != 0.0f || pae_obj->revolution_angle.end[2] != 0.0f) {
dest[1] += dist[2] * sinf(angle[2]);
dest[0] += dist[2] * cosf(angle[2]);
}
// Apply the curve.
glm_vec3_muladds(pae_obj->curve_length, 4.9f * t * (1.0f - t), dest);
}
static void calc_pos_and_up_vector(struct particle_object *po, struct particle_instance *pi, float t, vec3 pos, vec3 up_vector)
{
struct pae_object *pae_obj = po->pae_obj;
switch (pae_obj->move_type) {
case PARTICLE_MOVE_FIXED:
glm_vec3_add(po->pos.begin, pi->random_offset.begin, pos);
glm_vec3_copy(GLM_YUP, up_vector);
break;
case PARTICLE_MOVE_LINEAR:
calc_emitter_pos(po, pi, t, pos, up_vector);
switch (pae_obj->up_vector_type) {
case PARTICLE_UP_VECTOR_Y_AXIS:
case PARTICLE_UP_VECTOR_INSTANCE_MOVE:
glm_vec3_copy(GLM_YUP, up_vector);
break;
case PARTICLE_UP_VECTOR_OBJECT_MOVE:
if (glm_vec3_norm2(up_vector) == 0.0f)
glm_vec3_copy(GLM_XUP, up_vector);
else
glm_vec3_normalize(up_vector);
break;
}
break;
case PARTICLE_MOVE_EMITTER:
{
// Calculate the instance's initial and final position.
float t0 = glm_clamp_zo(glm_percent(pae_obj->begin_frame, pae_obj->end_frame, pi->begin_frame));
vec3_range inst_pos;
calc_emitter_pos(po, pi, t0, inst_pos.begin, NULL);
vec3 inst_move;
glm_vec3_copy(po->move_vec, inst_move);
switch (pae_obj->dir_type) {
case PARTICLE_DIR_TYPE_NORMAL:
glm_vec3_rotate(inst_move, pi->roll_angle, po->move_ortho);
glm_vec3_rotate(inst_move, pi->pitch_angle, po->move_vec);
break;
case PARTICLE_DIR_TYPE_XY_PLANE:
glm_vec3_rotate(inst_move, (pi->pitch_angle < GLM_PIf ? -1.0f : 1.0f) * pi->roll_angle, po->move_ortho);
break;
}
glm_vec3_copy(inst_pos.begin, inst_pos.end);
switch (pae_obj->child_move_dir_type) {
case PARTICLE_CHILD_MOVE_DIR_NORMAL:
glm_vec3_muladds(inst_move, pae_obj->child_length, inst_pos.end);
break;
case PARTICLE_CHILD_MOVE_DIR_REVERSE:
glm_vec3_muladds(inst_move, pae_obj->child_length, inst_pos.begin);
glm_vec3_negate(inst_move);
break;
}
// Current position of the instance.
glm_vec3_lerp(inst_pos.begin, inst_pos.end, t, pos);
// Calculate the up vector.
switch (pae_obj->up_vector_type) {
case PARTICLE_UP_VECTOR_Y_AXIS:
glm_vec3_copy(GLM_YUP, up_vector);
break;
case PARTICLE_UP_VECTOR_OBJECT_MOVE:
glm_vec3_copy(po->move_vec, up_vector);
break;
case PARTICLE_UP_VECTOR_INSTANCE_MOVE:
if (pae_obj->child_length != 0.0f)
glm_vec3_copy(inst_move, up_vector);
else
glm_vec3_copy(GLM_XUP, up_vector);
break;
}
if (pae_obj->dir_type == PARTICLE_DIR_TYPE_XY_PLANE) {
mat3 rot = {{ inst_move[1], -inst_move[0], 0.0f },
{ inst_move[0], inst_move[1], 0.0f },
{ 0.0f, 0.0f, 1.0f }};
glm_mat3_mulv(rot, up_vector, up_vector);
}
}
break;
}
}
static void calc_scale(struct pae_object *po, int frame, vec3 dest)
{
glm_vec3_broadcast(po->sizes2[min(frame, po->nr_sizes2 - 1)], dest);
if (po->nr_sizes_x)
dest[0] *= po->sizes_x[min(frame, po->nr_sizes_x - 1)];
if (po->nr_sizes_y)
dest[1] *= po->sizes_y[min(frame, po->nr_sizes_y - 1)];
}
void particle_object_calc_local_transform(struct RE_instance *inst, struct particle_object *po, struct particle_instance *pi, float frame, mat4 dest)
{
struct pae_object *pae_obj = po->pae_obj;
float t = glm_percent(pi->begin_frame, pi->end_frame, frame);
vec3 pos, up_vector;
calc_pos_and_up_vector(po, pi, t, pos, up_vector);
float rel_frame = frame - pi->begin_frame;
int cur_step = rel_frame;
int next_step = ceilf(rel_frame);
float step_frac = rel_frame - cur_step;
glm_translate_make(dest, pos);
if (pae_obj->type == PARTICLE_TYPE_BILLBOARD) {
mat4 view_mat;
RE_calc_view_matrix(&inst->plugin->camera, up_vector, view_mat);
mat3 rot;
glm_mat4_pick3t(view_mat, rot);
glm_mat4_ins3(rot, dest);
}
vec3 angles;
glm_vec3_lerp(pae_obj->rotation.begin, pae_obj->rotation.end, t, angles);
angles[0] *= -GLM_PIf / 180.0f;
angles[1] *= -GLM_PIf / 180.0f;
angles[2] *= GLM_PIf / 180.0f;
mat4 rotation_mat;
glm_euler_zxy(angles, rotation_mat);
glm_mat4_mul(dest, rotation_mat, dest);
if (pae_obj->nr_sizes2 > 0) {
vec3 scale, scale2;
calc_scale(pae_obj, cur_step, scale);
calc_scale(pae_obj, next_step, scale2);
glm_vec3_lerp(scale, scale2, step_frac, scale);
glm_scale(dest, scale);
} else {
glm_scale_uni(dest, glm_lerp(pae_obj->size[0], pae_obj->size[1], t));
}
glm_translate_x(dest, -pae_obj->offset_x);
glm_translate_y(dest, -pae_obj->offset_y);
}
float pae_object_calc_alpha(struct pae_object *po, struct particle_instance *pi, float frame)
{
frame -= pi->begin_frame;
if (frame < po->alpha_fadein_frame)
return glm_clamp_zo(frame / po->alpha_fadein_frame);
float total_frames = pi->end_frame - pi->begin_frame;
if (total_frames - po->alpha_fadeout_frame < frame)
return glm_clamp_zo((total_frames - frame) / po->alpha_fadeout_frame);
return 1.0;
}
+1061
View File
File diff suppressed because it is too large Load Diff
+990
View File
@@ -0,0 +1,990 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <limits.h>
#include <cglm/cglm.h>
#include "system4.h"
#include "system4/cg.h"
#include "system4/hashtable.h"
#include "3d_internal.h"
#include "asset_manager.h"
#include "reign.h"
#include "sact.h"
// TODO: Respect RE_plugin.shadow_map_resolution_level
#define SHADOW_WIDTH 512
#define SHADOW_HEIGHT 512
enum {
COLOR_TEXTURE_UNIT,
SPECULAR_TEXTURE_UNIT,
ALPHA_TEXTURE_UNIT,
LIGHT_TEXTURE_UNIT,
NORMAL_TEXTURE_UNIT,
SHADOW_TEXTURE_UNIT,
};
enum {
DIFFUSE_EMISSIVE = 0,
DIFFUSE_NORMAL = 1,
DIFFUSE_LIGHT_MAP = 2,
DIFFUSE_ENV_MAP = 3,
};
enum {
ALPHA_BLEND = 0,
ALPHA_TEST = 1,
ALPHA_MAP_BLEND = 2,
};
enum draw_phase {
DRAW_OPAQUE,
DRAW_TRANSPARENT,
};
static GLuint load_shader(const char *vertex_shader_path, const char *fragment_shader_path)
{
GLuint program = glCreateProgram();
GLuint vertex_shader = gfx_load_shader_file(vertex_shader_path, GL_VERTEX_SHADER);
GLuint fragment_shader = gfx_load_shader_file(fragment_shader_path, GL_FRAGMENT_SHADER);
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
// Bind vertex attributes to fixed locations, so that common VAO can be used
// by multiple programs.
glBindAttribLocation(program, VATTR_POS, "vertex_pos");
glBindAttribLocation(program, VATTR_NORMAL, "vertex_normal");
glBindAttribLocation(program, VATTR_UV, "vertex_uv");
glBindAttribLocation(program, VATTR_BONE_INDEX, "vertex_bone_index");
glBindAttribLocation(program, VATTR_BONE_WEIGHT, "vertex_bone_weight");
glBindAttribLocation(program, VATTR_LIGHT_UV, "vertex_light_uv");
glBindAttribLocation(program, VATTR_TANGENT, "vertex_tangent");
glLinkProgram(program);
GLint link_success;
glGetProgramiv(program, GL_LINK_STATUS, &link_success);
if (!link_success) {
GLint len;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &len);
char *infolog = xmalloc(len + 1);
glGetProgramInfoLog(program, len, NULL, infolog);
ERROR("Failed to link shader %s, %s: %s", vertex_shader_path, fragment_shader_path, infolog);
}
return program;
}
static void init_shadow_renderer(struct shadow_renderer *sr)
{
GLint orig_fbo;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_fbo);
sr->program = load_shader("shaders/reign_shadow.v.glsl", "shaders/reign_shadow.f.glsl");
sr->world_transform = glGetUniformLocation(sr->program, "world_transform");
sr->view_transform = glGetUniformLocation(sr->program, "view_transform");
sr->has_bones = glGetUniformLocation(sr->program, "has_bones");
sr->bone_matrices = glGetUniformLocation(sr->program, "bone_matrices");
glGenFramebuffers(1, &sr->fbo);
glGenTextures(1, &sr->texture);
glBindTexture(GL_TEXTURE_2D, sr->texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, sr->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, sr->texture, 0);
glDrawBuffers(0, NULL);
glReadBuffer(GL_NONE);
glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo);
}
static void destroy_shadow_renderer(struct shadow_renderer *sr)
{
glDeleteTextures(1, &sr->texture);
glDeleteFramebuffers(1, &sr->fbo);
glDeleteProgram(sr->program);
}
static void init_billboard_mesh(struct RE_renderer *r)
{
static const GLfloat vertices[] = {
// x, y, z, u, v
-1.0, 1.0, 0.0, 0.0, 0.0,
-1.0, -1.0, 0.0, 0.0, 1.0,
1.0, 1.0, 0.0, 1.0, 0.0,
1.0, -1.0, 0.0, 1.0, 1.0,
};
glGenVertexArrays(1, &r->billboard_vao);
glBindVertexArray(r->billboard_vao);
glGenBuffers(1, &r->billboard_attr_buffer);
glBindBuffer(GL_ARRAY_BUFFER, r->billboard_attr_buffer);
glEnableVertexAttribArray(VATTR_POS);
glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0);
glEnableVertexAttribArray(VATTR_UV);
glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12);
glDisableVertexAttribArray(VATTR_LIGHT_UV);
glVertexAttrib2f(VATTR_LIGHT_UV, 0.0, 0.0);
glDisableVertexAttribArray(VATTR_NORMAL);
glVertexAttrib3f(VATTR_NORMAL, 0.0, 0.0, 1.0);
glDisableVertexAttribArray(VATTR_TANGENT);
glVertexAttrib3f(VATTR_TANGENT, 1.0, 0.0, 0.0);
glDisableVertexAttribArray(VATTR_BONE_INDEX);
glVertexAttribI4i(VATTR_BONE_INDEX, 0, 0, 0, 0);
glDisableVertexAttribArray(VATTR_BONE_WEIGHT);
glVertexAttrib4f(VATTR_BONE_WEIGHT, 0.0, 0.0, 0.0, 0.0);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
static void destroy_billboard_mesh(struct RE_renderer *r)
{
glDeleteVertexArrays(1, &r->billboard_vao);
glDeleteBuffers(1, &r->billboard_attr_buffer);
}
struct RE_renderer *RE_renderer_new(struct texture *texture)
{
struct RE_renderer *r = xcalloc(1, sizeof(struct RE_renderer));
r->program = load_shader("shaders/reign.v.glsl", "shaders/reign.f.glsl");
r->world_transform = glGetUniformLocation(r->program, "world_transform");
r->view_transform = glGetUniformLocation(r->program, "view_transform");
r->texture = glGetUniformLocation(r->program, "tex");
r->local_transform = glGetUniformLocation(r->program, "local_transform");
r->proj_transform = glGetUniformLocation(r->program, "proj_transform");
r->normal_transform = glGetUniformLocation(r->program, "normal_transform");
r->alpha_mod = glGetUniformLocation(r->program, "alpha_mod");
r->has_bones = glGetUniformLocation(r->program, "has_bones");
r->bone_matrices = glGetUniformLocation(r->program, "bone_matrices");
r->ambient = glGetUniformLocation(r->program, "ambient");
for (int i = 0; i < NR_DIR_LIGHTS; i++) {
char buf[64];
sprintf(buf, "dir_lights[%d].dir", i);
r->dir_lights[i].dir = glGetUniformLocation(r->program, buf);
sprintf(buf, "dir_lights[%d].diffuse", i);
r->dir_lights[i].diffuse = glGetUniformLocation(r->program, buf);
sprintf(buf, "dir_lights[%d].globe_diffuse", i);
r->dir_lights[i].globe_diffuse = glGetUniformLocation(r->program, buf);
}
r->specular_light_dir = glGetUniformLocation(r->program, "specular_light_dir");
r->specular_strength = glGetUniformLocation(r->program, "specular_strength");
r->specular_shininess = glGetUniformLocation(r->program, "specular_shininess");
r->use_specular_map = glGetUniformLocation(r->program, "use_specular_map");
r->specular_texture = glGetUniformLocation(r->program, "specular_texture");
r->rim_exponent = glGetUniformLocation(r->program, "rim_exponent");
r->rim_color = glGetUniformLocation(r->program, "rim_color");
r->camera_pos = glGetUniformLocation(r->program, "camera_pos");
r->diffuse_type = glGetUniformLocation(r->program, "diffuse_type");
r->light_texture = glGetUniformLocation(r->program, "light_texture");
r->use_normal_map = glGetUniformLocation(r->program, "use_normal_map");
r->normal_texture = glGetUniformLocation(r->program, "normal_texture");
r->shadow_darkness = glGetUniformLocation(r->program, "shadow_darkness");
r->shadow_transform = glGetUniformLocation(r->program, "shadow_transform");
r->shadow_texture = glGetUniformLocation(r->program, "shadow_texture");
r->shadow_bias = glGetUniformLocation(r->program, "shadow_bias");
r->fog_type = glGetUniformLocation(r->program, "fog_type");
r->fog_near = glGetUniformLocation(r->program, "fog_near");
r->fog_far = glGetUniformLocation(r->program, "fog_far");
r->fog_color = glGetUniformLocation(r->program, "fog_color");
r->ls_params = glGetUniformLocation(r->program, "ls_params");
r->ls_light_dir = glGetUniformLocation(r->program, "ls_light_dir");
r->ls_light_color = glGetUniformLocation(r->program, "ls_light_color");
r->ls_sun_color = glGetUniformLocation(r->program, "ls_sun_color");
r->alpha_mode = glGetUniformLocation(r->program, "alpha_mode");
r->alpha_texture = glGetUniformLocation(r->program, "alpha_texture");
glGenRenderbuffers(1, &r->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, r->depth_buffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, texture->w, texture->h);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
init_shadow_renderer(&r->shadow);
init_billboard_mesh(r);
r->billboard_textures = ht_create(256);
return r;
}
bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no)
{
if (ht_get_int(r->billboard_textures, cg_no, NULL))
return true;
struct cg *cg = asset_cg_load(cg_no);
if (!cg)
return false;
struct billboard_texture *bt = xcalloc(1, sizeof(struct billboard_texture));
glGenTextures(1, &bt->texture);
glBindTexture(GL_TEXTURE_2D, bt->texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
bt->has_alpha = cg->metrics.has_alpha;
cg_free(cg);
ht_put_int(r->billboard_textures, cg_no, bt);
return true;
}
static void free_billboard_texture(void *value)
{
struct billboard_texture *bt = value;
glDeleteTextures(1, &bt->texture);
free(bt);
}
void RE_renderer_free(struct RE_renderer *r)
{
glDeleteProgram(r->program);
glDeleteRenderbuffers(1, &r->depth_buffer);
ht_foreach_value(r->billboard_textures, free_billboard_texture);
ht_free_int(r->billboard_textures);
destroy_billboard_mesh(r);
destroy_shadow_renderer(&r->shadow);
free(r);
}
void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out)
{
vec3 front = { 0.0, 0.0, -1.0 };
vec3 euler = {
glm_rad(camera->pitch + camera->quake_pitch),
glm_rad(camera->yaw + camera->quake_yaw),
glm_rad(camera->roll)
};
mat4 rot;
glm_euler(euler, rot);
glm_mat4_mulv3(rot, front, 0.0, front);
glm_look(camera->pos, front, up, out);
}
static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum draw_phase phase)
{
struct model *model = inst->model;
if (!inst->model)
return;
bool all_transparent = inst->alpha < 1.0f;
bool all_opaque = !model->has_transparent_material && inst->alpha >= 1.0f;
if ((phase == DRAW_OPAQUE && all_transparent) || (phase == DRAW_TRANSPARENT && all_opaque))
return;
if (inst->local_transform_needs_update)
RE_instance_update_local_transform(inst);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, inst->local_transform[0]);
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, inst->normal_transform[0]);
glUniform1f(r->alpha_mod, inst->alpha);
vec3 ambient;
glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
glUniform3fv(r->ambient, 1, ambient);
bool draw_shadow = inst->draw_shadow && inst->plugin->shadow_mode;
if (draw_shadow) {
glActiveTexture(GL_TEXTURE0 + SHADOW_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, r->shadow.texture);
glUniform1i(r->shadow_texture, SHADOW_TEXTURE_UNIT);
}
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
struct material *material = &model->materials[mesh->material];
bool is_transparent = (material->is_transparent && !(mesh->flags & MESH_SPRITE)) || inst->alpha < 1.0f;
if (phase != (is_transparent ? DRAW_TRANSPARENT : DRAW_OPAQUE))
continue;
glUniform1i(r->fog_type, (inst->plugin->fog_mode && !(mesh->flags & MESH_NOLIGHTING))
? inst->plugin->fog_type : 0);
GLboolean use_specular_map = GL_FALSE;
if (inst->plugin->specular_mode && !(mesh->flags & MESH_NOLIGHTING)) {
glUniform1f(r->specular_strength, material->specular_strength);
glUniform1f(r->specular_shininess, material->specular_shininess);
if (material->specular_map) {
glActiveTexture(GL_TEXTURE0 + SPECULAR_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->specular_map);
glUniform1i(r->specular_texture, SPECULAR_TEXTURE_UNIT);
use_specular_map = GL_TRUE;
}
} else {
glUniform1f(r->specular_strength, 0.0);
glUniform1f(r->specular_shininess, 0.0);
}
glUniform1i(r->use_specular_map, use_specular_map);
glUniform1f(r->rim_exponent, material->rim_exponent);
glUniform3fv(r->rim_color, 1, material->rim_color);
glActiveTexture(GL_TEXTURE0 + COLOR_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->color_map);
glUniform1i(r->texture, COLOR_TEXTURE_UNIT);
if (draw_shadow && !(mesh->flags & MESH_BOTH))
glUniform1f(r->shadow_darkness, material->shadow_darkness);
else
glUniform1f(r->shadow_darkness, 0.0f);
if (mesh->flags & MESH_ENVMAP) {
glUniform1i(r->diffuse_type, DIFFUSE_ENV_MAP);
} else if (mesh->flags & MESH_NOLIGHTING) {
glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE);
} else if (material->light_map && inst->plugin->light_map_mode) {
glUniform1i(r->diffuse_type, DIFFUSE_LIGHT_MAP);
glActiveTexture(GL_TEXTURE0 + LIGHT_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->light_map);
glUniform1i(r->light_texture, LIGHT_TEXTURE_UNIT);
} else {
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
}
if (material->normal_map && inst->draw_bump && inst->plugin->bump_mode) {
glUniform1i(r->use_normal_map, GL_TRUE);
glActiveTexture(GL_TEXTURE0 + NORMAL_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->normal_map);
glUniform1i(r->normal_texture, NORMAL_TEXTURE_UNIT);
} else {
glUniform1i(r->use_normal_map, GL_FALSE);
}
if (material->alpha_map) {
glUniform1i(r->alpha_mode, ALPHA_MAP_BLEND);
glActiveTexture(GL_TEXTURE0 + ALPHA_TEXTURE_UNIT);
glBindTexture(GL_TEXTURE_2D, material->alpha_map);
glUniform1i(r->alpha_texture, ALPHA_TEXTURE_UNIT);
} else if (material->flags & MATERIAL_SPRITE || mesh->flags & MESH_SPRITE) {
glUniform1i(r->alpha_mode, ALPHA_TEST);
} else {
glUniform1i(r->alpha_mode, ALPHA_BLEND);
}
glBindVertexArray(mesh->vao);
if (mesh->nr_indices)
glDrawElements(GL_TRIANGLES, mesh->nr_indices, GL_UNSIGNED_SHORT, NULL);
else
glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
static void render_static_model(struct RE_instance *inst, struct RE_renderer *r, enum draw_phase phase)
{
if (!inst->draw)
return;
glUniform1i(r->has_bones, GL_FALSE);
render_model(inst, r, phase);
}
static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r, enum draw_phase phase)
{
if (!inst->draw)
return;
struct model *model = inst->model;
if (!model)
return;
if (model->nr_bones > 0 && inst->motion) {
glUniform1i(r->has_bones, GL_TRUE);
glUniformMatrix4fv(r->bone_matrices, model->nr_bones, GL_FALSE, inst->bone_transforms[0][0]);
} else {
glUniform1i(r->has_bones, GL_FALSE);
}
render_model(inst, r, phase);
if (inst->shadow_volume_instance && phase == DRAW_TRANSPARENT)
render_static_model(inst->shadow_volume_instance, r, phase);
}
static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat, enum draw_phase phase)
{
if (!inst->draw)
return;
int cg_no = inst->motion->current_frame;
struct billboard_texture *bt = ht_get_int(r->billboard_textures, cg_no, NULL);
if (!bt)
return;
bool is_transparent = bt->has_alpha || inst->alpha < 1.0f;
if (phase != (is_transparent ? DRAW_TRANSPARENT : DRAW_OPAQUE))
return;
mat4 local_transform;
glm_translate_make(local_transform, inst->pos);
mat3 rot;
glm_mat4_pick3t(view_mat, rot);
glm_mat4_ins3(rot, local_transform);
glm_scale(local_transform, inst->scale);
// Billboard instances are bottomed at y=0.
glm_translate_y(local_transform, 1.0);
mat3 normal_transform;
// This should be safe because billboards do not have non-uniform scaling.
glm_mat4_pick3(local_transform, normal_transform);
vec3 ambient;
glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
glUniform3fv(r->ambient, 1, ambient);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, normal_transform[0]);
glUniform1i(r->has_bones, GL_FALSE);
glUniform1f(r->alpha_mod, inst->alpha);
glUniform1f(r->specular_strength, 0.0);
glUniform1f(r->specular_shininess, 0.0);
glUniform1i(r->use_specular_map, GL_FALSE);
glUniform1f(r->rim_exponent, 0.0);
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
glUniform1i(r->use_normal_map, GL_FALSE);
glUniform1f(r->shadow_darkness, 0.0f);
glUniform1i(r->alpha_mode, ALPHA_BLEND);
glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0);
switch (inst->draw_type) {
case RE_DRAW_TYPE_NORMAL:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
break;
case RE_DRAW_TYPE_ADDITIVE:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
}
glDepthFunc(GL_LEQUAL);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bt->texture);
glUniform1i(r->texture, 0);
glBindVertexArray(r->billboard_vao);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
glDepthFunc(GL_LESS);
}
static void render_billboard_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame)
{
struct pae_object *pae_obj = po->pae_obj;
if (pae_obj->nr_textures == 0)
return;
glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE);
glUniform1i(r->fog_type, 0);
glActiveTexture(GL_TEXTURE0);
glUniform1i(r->texture, 0);
glBindVertexArray(r->billboard_vao);
for (int index = 0; index < pae_obj->nr_particles; index++) {
struct particle_instance *pi = &po->instances[index];
if (frame < pi->begin_frame || pi->end_frame <= frame)
continue;
int step = (int)((frame - pi->begin_frame) / pae_obj->texture_anime_frame);
struct billboard_texture *bt = ht_get(inst->effect->pae->textures, pae_obj->textures[step % pae_obj->nr_textures], NULL);
if (!bt)
continue;
glBindTexture(GL_TEXTURE_2D, bt->texture);
float alpha = pae_object_calc_alpha(pae_obj, pi, frame);
if (pae_obj->blend_type == PARTICLE_BLEND_ADDITIVE && !bt->has_alpha)
alpha *= alpha; // why...
glUniform1f(r->alpha_mod, alpha);
mat4 local_transform;
particle_object_calc_local_transform(inst, po, pi, frame, local_transform);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, local_transform[0]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame)
{
struct pae_object *pae_obj = po->pae_obj;
struct model *model = pae_obj->model;
if (!model)
return;
glUniform1i(r->diffuse_type, DIFFUSE_NORMAL);
glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0);
for (int index = 0; index < pae_obj->nr_particles; index++) {
struct particle_instance *pi = &po->instances[index];
if (frame < pi->begin_frame || pi->end_frame <= frame)
continue;
float alpha = pae_object_calc_alpha(pae_obj, pi, frame);
glUniform1f(r->alpha_mod, alpha);
mat4 local_transform;
particle_object_calc_local_transform(inst, po, pi, frame, local_transform);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, local_transform[0]);
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
struct material *material = &model->materials[mesh->material];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, material->color_map);
glUniform1i(r->texture, 0);
glBindVertexArray(mesh->vao);
glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
}
static void render_particle_effect(struct RE_instance *inst, struct RE_renderer *r, enum draw_phase phase)
{
// NOTE: inst->draw flag has no effect for particle effects.
if (!inst->effect || phase == DRAW_OPAQUE)
return;
vec3 ambient;
glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
glUniform3fv(r->ambient, 1, ambient);
glUniform1i(r->has_bones, GL_FALSE);
glUniform1f(r->specular_strength, 0.0);
glUniform1f(r->specular_shininess, 0.0);
glUniform1i(r->use_specular_map, GL_FALSE);
glUniform1f(r->rim_exponent, 0.0);
glUniform1i(r->use_normal_map, GL_FALSE);
glUniform1f(r->shadow_darkness, 0.0f);
glUniform1i(r->alpha_mode, ALPHA_BLEND);
glDepthMask(GL_FALSE);
for (int i = 0; i < inst->effect->pae->nr_objects; i++) {
struct particle_object *po = &inst->effect->objects[i];
switch (po->pae_obj->blend_type) {
case PARTICLE_BLEND_NORMAL:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
break;
case PARTICLE_BLEND_ADDITIVE:
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
break;
}
switch (po->pae_obj->type) {
case PARTICLE_TYPE_BILLBOARD:
render_billboard_particles(r, inst, po, inst->motion->current_frame);
break;
case PARTICLE_TYPE_POLYGON_OBJECT:
render_polygon_particles(r, inst, po, inst->motion->current_frame);
break;
case PARTICLE_TYPE_SWORD_BLUR: // unused
case PARTICLE_TYPE_CAMERA_QUAKE: // handled in particle_effect_update()
break;
}
}
glDepthMask(GL_TRUE);
}
static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat, enum draw_phase phase)
{
switch (inst->type) {
case RE_ITYPE_STATIC:
render_static_model(inst, r, phase);
break;
case RE_ITYPE_SKINNED:
render_skinned_model(inst, r, phase);
break;
case RE_ITYPE_BILLBOARD:
render_billboard(inst, r, view_mat, phase);
break;
case RE_ITYPE_PARTICLE_EFFECT:
render_particle_effect(inst, r, phase);
break;
default:
break;
}
}
static bool calc_shadow_light_transform(struct RE_plugin *plugin, mat4 dest)
{
// Compute a bounding sphere of shadow casters.
vec4 bounding_sphere = {};
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst || !inst->draw || !inst->make_shadow || !inst->model)
continue;
if (bounding_sphere[3] > 0.0f)
glm_sphere_merge(inst->bounding_sphere, bounding_sphere, inst->bounding_sphere);
else
glm_vec4_copy(inst->bounding_sphere, bounding_sphere);
}
float radius = bounding_sphere[3] * 1.2f; // Add some padding.
if (radius <= 0.0f)
return false;
// Create a orthographic frustum that contains the bounding sphere.
mat4 view_matrix;
glm_look(bounding_sphere, plugin->shadow_map_light_dir, GLM_YUP, view_matrix);
mat4 proj_matrix;
glm_ortho(-radius, radius, -radius, radius, -radius, radius, proj_matrix);
glm_mat4_mul(proj_matrix, view_matrix, dest);
return true;
}
static void render_shadow_map(struct RE_plugin *plugin, mat4 light_space_transform)
{
if (!calc_shadow_light_transform(plugin, light_space_transform)) {
// No shadow casters, but proceed anyway to clear the shadow texture.
glm_mat4_identity(light_space_transform);
}
struct RE_renderer *r = plugin->renderer;
GLint orig_fbo, orig_viewport[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_fbo);
glGetIntegerv(GL_VIEWPORT, orig_viewport);
glBindFramebuffer(GL_FRAMEBUFFER, r->shadow.fbo);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(r->shadow.program);
glUniformMatrix4fv(r->shadow.view_transform, 1, GL_FALSE, light_space_transform[0]);
glEnable(GL_DEPTH_TEST);
// Render the shadow casters.
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst || !inst->draw || !inst->make_shadow || !inst->model)
continue;
struct model *model = inst->model;
if (model->nr_bones > 0) {
glUniform1i(r->shadow.has_bones, GL_TRUE);
glUniformMatrix4fv(r->shadow.bone_matrices, model->nr_bones, GL_FALSE, inst->bone_transforms[0][0]);
} else {
glUniform1i(r->shadow.has_bones, GL_FALSE);
}
glUniformMatrix4fv(r->shadow.world_transform, 1, GL_FALSE, inst->local_transform[0]);
for (int j = 0; j < model->nr_meshes; j++) {
struct mesh *mesh = &model->meshes[j];
if (mesh->flags & MESH_NOMAKESHADOW)
continue;
glBindVertexArray(mesh->vao);
glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices);
}
glBindVertexArray(0);
}
glDisable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo);
glViewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]);
}
static void render_back_cg(struct texture *dst, struct RE_back_cg *bcg, struct RE_renderer *r)
{
if (!bcg->show || !bcg->texture.handle)
return;
int sw = bcg->texture.w;
int sh = bcg->texture.h;
gfx_copy_stretch_blend_amap_alpha(dst, bcg->x, bcg->y, sw * bcg->mag, sh * bcg->mag, &bcg->texture, 0, 0, sw, sh, bcg->blend_rate * 255);
}
static void setup_lights(struct RE_plugin *plugin)
{
struct RE_renderer *r = plugin->renderer;
glUniform3fv(r->camera_pos, 1, plugin->camera.pos);
int light_index = 0;
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst)
continue;
switch (inst->type) {
case RE_ITYPE_DIRECTIONAL_LIGHT:
if (light_index >= NR_DIR_LIGHTS) {
WARNING("too many directional lights");
break;
}
glUniform3fv(r->dir_lights[light_index].dir, 1, inst->vec);
glUniform3fv(r->dir_lights[light_index].diffuse, 1, inst->diffuse);
glUniform3fv(r->dir_lights[light_index].globe_diffuse, 1, inst->globe_diffuse);
light_index++;
break;
case RE_ITYPE_SPECULAR_LIGHT:
glUniform3fv(r->specular_light_dir, 1, inst->vec);
break;
default:
break;
}
}
for (; light_index < NR_DIR_LIGHTS; light_index++) {
const vec3 zero = {0.0, 0.0, 0.0};
glUniform3fv(r->dir_lights[light_index].dir, 1, zero);
glUniform3fv(r->dir_lights[light_index].diffuse, 1, zero);
glUniform3fv(r->dir_lights[light_index].globe_diffuse, 1, zero);
}
}
static int cmp_instances_by_z(const void *lhs, const void *rhs)
{
struct RE_instance *l = *(struct RE_instance **)lhs;
struct RE_instance *r = *(struct RE_instance **)rhs;
float lz = l ? l->z_from_camera : FLT_MAX;
float rz = r ? r->z_from_camera : FLT_MAX;
return (lz > rz) - (lz < rz); // ascending order.
}
static struct RE_instance **sort_instances(struct RE_plugin *plugin, mat4 view_transform)
{
struct RE_instance **instances = xmalloc(plugin->nr_instances * sizeof(struct RE_instance *));
memcpy(instances, plugin->instances, plugin->nr_instances * sizeof(struct RE_instance *));
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = instances[i];
if (!inst)
continue;
vec3 center;
if (inst->model) {
glm_aabb_center(inst->model->aabb, center);
if (inst->local_transform_needs_update)
RE_instance_update_local_transform(inst);
glm_mat4_mulv3(inst->local_transform, center, 1.0, center);
} else {
glm_vec3_copy(inst->pos, center);
}
glm_mat4_mulv3(view_transform, center, 1.0f, center);
inst->z_from_camera = center[2];
}
qsort(instances, plugin->nr_instances, sizeof(struct RE_instance *), cmp_instances_by_z);
return instances;
}
void RE_render(struct sact_sprite *sp)
{
struct RE_plugin *plugin = (struct RE_plugin *)sp->plugin;
struct RE_renderer *r = plugin->renderer;
if (!r)
return;
sprite_dirty(sp);
struct texture *texture = sprite_get_texture(sp);
mat4 shadow_transform;
if (plugin->shadow_mode)
render_shadow_map(plugin, shadow_transform);
else
glm_mat4_identity(shadow_transform);
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, texture, 0, 0, texture->w, texture->h);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, r->depth_buffer);
if (glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
ERROR("Incomplete framebuffer");
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw background CGs.
glDisable(GL_DEPTH_TEST);
for (int i = 0; i < RE_NR_BACK_CGS; i++)
render_back_cg(texture, &plugin->back_cg[i], r);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
mat4 view_transform;
RE_calc_view_matrix(&plugin->camera, GLM_YUP, view_transform);
// Tweak the projection transform so that the rendering result is vertically
// flipped. If we render the scene normally, the resulting image will be
// bottom-up (the first pixel is at the bottom-left), but we want a top-down
// image (the first pixel is at the top-left). This changes the coordinate
// system from right-handed to left-handed, we also need to reverse the
// winding order.
plugin->proj_transform[1][1] *= -1;
glFrontFace(GL_CW);
glUseProgram(r->program);
glUniformMatrix4fv(r->view_transform, 1, GL_FALSE, view_transform[0]);
glUniformMatrix4fv(r->proj_transform, 1, GL_FALSE, plugin->proj_transform[0]);
glUniformMatrix4fv(r->shadow_transform, 1, GL_FALSE, shadow_transform[0]);
glUniform1f(r->shadow_bias, plugin->shadow_bias);
if (plugin->fog_mode) {
switch (plugin->fog_type) {
case RE_FOG_NONE:
break;
case RE_FOG_LINEAR:
glUniform1f(r->fog_near, plugin->fog_near);
glUniform1f(r->fog_far, plugin->fog_far);
glUniform3fv(r->fog_color, 1, plugin->fog_color);
break;
case RE_FOG_LIGHT_SCATTERING:
glUniform4f(r->ls_params, plugin->ls_beta_r, plugin->ls_beta_m, plugin->ls_g, plugin->ls_distance);
glUniform3fv(r->ls_light_dir, 1, plugin->ls_light_dir);
glUniform3fv(r->ls_light_color, 1, plugin->ls_light_color);
glUniform3fv(r->ls_sun_color, 1, plugin->ls_sun_color);
break;
}
}
glEnable(GL_BLEND);
setup_lights(plugin);
// Sort instances by z-order.
struct RE_instance **sorted_instances = sort_instances(plugin, view_transform);
// Render opaque instances, from nearest to farthest.
for (int i = plugin->nr_instances - 1; i >= 0; i--) {
struct RE_instance *inst = sorted_instances[i];
if (!inst)
continue;
render_instance(inst, r, view_transform, DRAW_OPAQUE);
}
// Render transparent instances, from farthest to nearest.
for (int i = 0; i < plugin->nr_instances; i++) {
struct RE_instance *inst = sorted_instances[i];
if (!inst)
continue;
render_instance(inst, r, view_transform, DRAW_TRANSPARENT);
}
free(sorted_instances);
plugin->proj_transform[1][1] *= -1;
glFrontFace(GL_CCW);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glUseProgram(0);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
struct height_detector {
GLushort *buf;
vec3 aabb[2];
};
struct height_detector *RE_renderer_create_height_detector(struct RE_renderer *r, struct model *model)
{
struct height_detector *hd = xcalloc(1, sizeof(struct height_detector));
vec3 aabb[2];
memcpy(aabb, model->aabb, sizeof(aabb));
// Add some Y padding.
aabb[0][1] -= 1.0;
aabb[1][1] += 1.0;
memcpy(hd->aabb, aabb, sizeof(aabb));
// Set up an orthographic projection matrix looking down the instance from
// right above.
mat4 view_matrix, proj_matrix;
glm_mat4_identity(view_matrix);
glm_rotate_x(view_matrix, glm_rad(90.0), view_matrix);
glm_aabb_transform(aabb, view_matrix, aabb);
glm_ortho_aabb(aabb, proj_matrix);
GLint orig_fbo, orig_viewport[4];
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &orig_fbo);
glGetIntegerv(GL_VIEWPORT, orig_viewport);
// Since OpenGL ES does not allow reading from depth textures, create a
// color texture and render depth values into it.
GLuint color_texture;
glGenTextures(1, &color_texture);
glBindTexture(GL_TEXTURE_2D, color_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_RED_INTEGER, GL_UNSIGNED_SHORT, NULL);
glBindFramebuffer(GL_FRAMEBUFFER, r->shadow.fbo);
GLenum draw_buffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, draw_buffers);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_texture, 0);
glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT);
glClear(GL_DEPTH_BUFFER_BIT);
glUseProgram(r->shadow.program);
glUniformMatrix4fv(r->shadow.world_transform, 1, GL_FALSE, view_matrix[0]);
glUniformMatrix4fv(r->shadow.view_transform, 1, GL_FALSE, proj_matrix[0]);
glUniform1i(r->shadow.has_bones, GL_FALSE);
glEnable(GL_DEPTH_TEST);
// Render the model.
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
glBindVertexArray(mesh->vao);
glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices);
}
glBindVertexArray(0);
glFinish();
hd->buf = xmalloc(SHADOW_WIDTH * SHADOW_HEIGHT * sizeof(GLushort));
glReadPixels(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT, GL_RED_INTEGER, GL_UNSIGNED_SHORT, hd->buf);
glDisable(GL_DEPTH_TEST);
glDrawBuffers(0, NULL);
glReadBuffer(GL_NONE);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, orig_fbo);
glViewport(orig_viewport[0], orig_viewport[1], orig_viewport[2], orig_viewport[3]);
glDeleteTextures(1, &color_texture);
return hd;
}
void RE_renderer_free_height_detector(struct height_detector *hd)
{
free(hd->buf);
free(hd);
}
bool RE_renderer_detect_height(struct height_detector *hd, float x, float z, float *y_out)
{
float minx = hd->aabb[0][0];
float maxx = hd->aabb[1][0];
float miny = hd->aabb[0][1];
float maxy = hd->aabb[1][1];
float minz = hd->aabb[0][2];
float maxz = hd->aabb[1][2];
if (x < minx || x > maxx || z < minz || z > maxz)
return false;
int px = glm_percent(minx, maxx, x) * SHADOW_WIDTH;
int pz = glm_percent(maxz, minz, z) * SHADOW_HEIGHT;
GLushort val = hd->buf[pz * SHADOW_WIDTH + px];
if (!val)
return false;
*y_out = glm_lerp(maxy, miny, val / 65535.0f);
return true;
}
+325 -137
View File
@@ -29,10 +29,12 @@
#include "system4/cg.h"
#include "system4/file.h"
#include "system4/hashtable.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "xsystem4.h"
#include "asset_manager.h"
#include "gfx/font.h"
enum archive_type {
AR_TYPE_ALD,
@@ -54,18 +56,280 @@ const char *asset_strtype(enum asset_type type)
return "Invalid";
}
static struct archive *archives[ASSET_TYPE_MAX] = {0};
#define MAX_ARCHIVES 8
struct asset_manager {
bool (*load_archive)(struct asset_manager *manager, const char *name);
bool (*exists_by_id)(struct asset_manager *manager, int id);
bool (*exists_by_name)(struct asset_manager *manager, const char *name, int *id_out);
struct archive_data *(*get_by_id)(struct asset_manager *manager, int id);
struct archive_data *(*get_by_name)(struct asset_manager *manager, const char *name, int *id_out);
};
// XXX: also used for AFAv1 in Daiteikoku, Shaman's Sanctuary
struct asset_manager_ald {
struct asset_manager manager;
struct archive *archive;
};
struct asset_manager_afa {
struct asset_manager manager;
struct afa_archive *archives[MAX_ARCHIVES];
struct hash_table *index;
};
static struct asset_manager *assets[ASSET_TYPE_MAX] = {0};
bool asset_manager_load_archive(enum asset_type type, const char *archive_name)
{
if (!assets[type])
return false;
if (!assets[type]->load_archive)
ERROR("load_archive not supported on this archive type");
return assets[type]->load_archive(assets[type], archive_name);
}
bool asset_exists(enum asset_type type, int id)
{
if (!assets[type])
return false;
return assets[type]->exists_by_id(assets[type], id);
}
bool asset_exists_by_name(enum asset_type type, const char *name, int *id_out)
{
if (!assets[type])
return false;
if (!assets[type]->exists_by_name)
ERROR("exists_by_name not supported on this archive type");
return assets[type]->exists_by_name(assets[type], name, id_out);
}
struct archive_data *asset_get(enum asset_type type, int id)
{
if (!assets[type])
return NULL;
return assets[type]->get_by_id(assets[type], id);
}
struct archive_data *asset_get_by_name(enum asset_type type, const char *name, int *id_out)
{
if (!assets[type])
return NULL;
if (!assets[type]->get_by_name)
ERROR("get_by_name not supported on this archive type");
return assets[type]->get_by_name(assets[type], name, id_out);
}
struct cg *asset_cg_load(int id)
{
struct archive_data *data = asset_get(ASSET_CG, id);
if (!data)
return NULL;
struct cg *cg = cg_load_data(data);
archive_free_data(data);
return cg;
}
struct cg *asset_cg_load_by_name(const char *name, int *id_out)
{
struct archive_data *data = asset_get_by_name(ASSET_CG, name, id_out);
if (!data)
return NULL;
struct cg *cg = cg_load_data(data);
archive_free_data(data);
return cg;
}
bool asset_cg_get_metrics(int id, struct cg_metrics *metrics)
{
struct archive_data *data = asset_get(ASSET_CG, id);
if (!data)
return false;
bool r = cg_get_metrics_data(data, metrics);
archive_free_data(data);
return r;
}
bool asset_cg_get_metrics_by_name(const char *name, struct cg_metrics *metrics)
{
struct archive_data *data = asset_get_by_name(ASSET_CG, name, NULL);
if (!data)
return false;
bool r = cg_get_metrics_data(data, metrics);
archive_free_data(data);
return r;
}
static bool ald_exists_by_id(struct asset_manager *_manager, int id)
{
struct asset_manager_ald *manager = (struct asset_manager_ald*)_manager;
return archive_exists(manager->archive, id - 1);
}
static struct archive_data *ald_get_by_id(struct asset_manager *_manager, int id)
{
struct asset_manager_ald *manager = (struct asset_manager_ald*)_manager;
return archive_get(manager->archive, id - 1);
}
static bool afa_load_archive(struct asset_manager *_manager, const char *name)
{
struct asset_manager_afa *manager = (struct asset_manager_afa*)_manager;
if (manager->archives[MAX_ARCHIVES-1])
ERROR("Archive limit exceeded");
char path[PATH_MAX];
snprintf(path, PATH_MAX, "%s.afa", name);
int error;
struct afa_archive *ar = afa_open(path, MMAP_IF_64BIT, &error);
if (!ar) {
snprintf(path, PATH_MAX, "%s.AFA", name);
ar = afa_open(path, MMAP_IF_64BIT, &error);
if (!ar) {
WARNING("Failed to open archive: %s", display_utf0(path));
return false;
}
}
for (int i = MAX_ARCHIVES - 1; i > 0; i--) {
manager->archives[i] = manager->archives[i-1];
}
manager->archives[0] = ar;
// index needs to be rebuilt
if (manager->index) {
ht_free(manager->index);
manager->index = NULL;
}
return true;
}
static bool _afa_get_by_id(struct asset_manager *_manager, int id, struct afa_archive **ar_out, int *no_out)
{
struct asset_manager_afa *manager = (struct asset_manager_afa*)_manager;
uint32_t no = id - 1;
for (int i = 0; i < MAX_ARCHIVES && manager->archives[i]; i++) {
if (no < manager->archives[i]->nr_files) {
*ar_out = manager->archives[i];
*no_out = no;
return true;
}
no -= manager->archives[i]->nr_files;
}
return false;
}
static bool afa_exists_by_id(struct asset_manager *manager, int id)
{
int no;
struct afa_archive *ar;
return _afa_get_by_id(manager, id, &ar, &no);
}
static struct archive_data *afa_get_by_id(struct asset_manager *manager, int id)
{
int no;
struct afa_archive *ar;
if (!_afa_get_by_id(manager, id, &ar, &no))
return NULL;
// XXX: we don't use archive_get here because it will return the wrong thing
// for AFAv1 archives when not using integer indices
struct archive_data *data = afa_entry_to_descriptor(ar, &ar->files[no]);
if (data)
archive_load_file(data);
return data;
}
static void afa_index_archive(struct hash_table *index, struct afa_archive *ar, unsigned base)
{
for (unsigned i = 0; i < ar->nr_files; i++) {
// normalize case and remove file extension from file name
char *name = strdup(ar->files[i].name->text);
char *dot = strrchr(name, '.');
if (dot)
*dot = '\0';
sjis_toupper(name);
// add file to index
ht_put(index, name, (void*)((uintptr_t)base + i + 1));
free(name);
}
}
static bool _afa_get_by_name(struct asset_manager *_manager, const char *_name,
struct afa_archive **ar_out, int *no_out, int *id_out)
{
struct asset_manager_afa *manager = (struct asset_manager_afa*)_manager;
// initialize index lazily
if (!manager->index) {
manager->index = ht_create(4096);
unsigned base = 0;
for (unsigned i = 0; i < MAX_ARCHIVES && manager->archives[i]; i++) {
afa_index_archive(manager->index, manager->archives[i], base);
base += manager->archives[i]->nr_files;
}
}
// normalize name and get id from index
char *name = strdup(_name);
sjis_toupper(name);
char *dot = strrchr(name, '.');
if (dot)
*dot = '\0';
uintptr_t id = (uintptr_t)ht_get(manager->index, name, NULL);
free(name);
if (!id)
return false;
if (id_out)
*id_out = id;
return _afa_get_by_id(_manager, id, ar_out, no_out);
}
static bool afa_exists_by_name(struct asset_manager *manager, const char *name, int *id_out)
{
int no;
struct afa_archive *ar;
return _afa_get_by_name(manager, name, &ar, &no, id_out);
}
static struct archive_data *afa_get_by_name(struct asset_manager *manager, const char *name, int *id_out)
{
int no;
struct afa_archive *ar;
if (!_afa_get_by_name(manager, name, &ar, &no, id_out))
return NULL;
return archive_get(&ar->ar, no);
}
static void _ald_init(enum asset_type type, struct archive *ar)
{
struct asset_manager_ald *manager = xcalloc(1, sizeof(struct asset_manager_ald));
manager->manager.exists_by_id = ald_exists_by_id;
manager->manager.get_by_id = ald_get_by_id;
manager->manager.load_archive = NULL;
manager->manager.exists_by_name = NULL;
manager->manager.get_by_name = NULL;
manager->archive = ar;
assets[type] = &manager->manager;
}
static void ald_init(enum asset_type type, char **files, int count)
{
if (count < 1)
return;
if (archives[type])
if (assets[type])
WARNING("Multiple asset archives for type %s", asset_strtype(type));
int error = ARCHIVE_SUCCESS;
archives[type] = ald_open(files, count, ARCHIVE_MMAP, &error);
if (error)
int error;
struct archive *ar = ald_open(files, count, MMAP_IF_64BIT, &error);
if (!ar)
ERROR("Failed to open ALD file: %s", archive_strerror(error));
_ald_init(type, ar);
for (int i = 0; i < count; i++) {
free(files[i]);
}
@@ -75,13 +339,27 @@ static void afa_init(enum asset_type type, char *file)
{
if (!file)
return;
if (archives[type])
if (assets[type])
WARNING("Multiple asset archives for type %s", asset_strtype(type));
int error = ARCHIVE_SUCCESS;
archives[type] = (struct archive*)afa_open(file, ARCHIVE_MMAP, &error);
if (error != ARCHIVE_SUCCESS) {
int error;
struct afa_archive *ar = afa_open(file, MMAP_IF_64BIT, &error);
if (!ar)
ERROR("Failed to open AFA file: %s", archive_strerror(error));
if (id_indexed_afa) {
_ald_init(type, &ar->ar);
} else {
struct asset_manager_afa *manager = xcalloc(1, sizeof(struct asset_manager_afa));
manager->manager.load_archive = afa_load_archive;
manager->manager.exists_by_id = afa_exists_by_id;
manager->manager.exists_by_name = afa_exists_by_name;
manager->manager.get_by_id = afa_get_by_id;
manager->manager.get_by_name = afa_get_by_name;
manager->archives[0] = ar;
assets[type] = &manager->manager;
}
free(file);
}
@@ -100,91 +378,98 @@ void asset_manager_init(void)
int ald_count[ASSET_TYPE_MAX] = {0};
char *afa_filenames[ASSET_TYPE_MAX] = {0};
DIR *dir;
struct dirent *d;
UDIR *dir;
char *d_name;
if (!(dir = opendir(config.game_dir))) {
ERROR("Failed to open directory: %s", config.game_dir);
if (!(dir = opendir_utf8(config.game_dir))) {
ERROR("Failed to open directory: %s", display_utf0(config.game_dir));
}
char *base = get_base_name(config.ain_filename);
size_t base_len = strlen(base);
// get ALD filenames
while ((d = readdir(dir))) {
while ((d_name = readdir_utf8(dir))) {
// archive filename must begin with ain filename
if (strncmp(base, d->d_name, base_len))
continue;
const char *ext = file_extension(d->d_name);
if (strncmp(base, d_name, base_len))
goto loop_next;
const char *ext = file_extension(d_name);
if (!ext)
continue;
goto loop_next;
if (!strcasecmp(ext, "ald")) {
int dno = toupper(d->d_name[base_len+1]) - 'A';
int dno = toupper(d_name[base_len+1]) - 'A';
if (dno < 0 || dno >= ALD_FILEMAX) {
WARNING("Invalid ALD index: %s", d->d_name);
continue;
WARNING("Invalid ALD index: %s", display_utf0(d_name));
goto loop_next;
}
switch (d->d_name[base_len]) {
switch (d_name[base_len]) {
case 'b':
case 'B':
ald_filenames[ASSET_BGM][dno] = path_join(config.game_dir, d->d_name);
ald_filenames[ASSET_BGM][dno] = path_join(config.game_dir, d_name);
ald_count[ASSET_BGM] = max(ald_count[ASSET_BGM], dno+1);
break;
case 'g':
case 'G':
ald_filenames[ASSET_CG][dno] = path_join(config.game_dir, d->d_name);
ald_filenames[ASSET_CG][dno] = path_join(config.game_dir, d_name);
ald_count[ASSET_CG] = max(ald_count[ASSET_CG], dno+1);
break;
case 'w':
case 'W':
ald_filenames[ASSET_SOUND][dno] = path_join(config.game_dir, d->d_name);
ald_filenames[ASSET_SOUND][dno] = path_join(config.game_dir, d_name);
ald_count[ASSET_SOUND] = max(ald_count[ASSET_SOUND], dno+1);
break;
case 'd':
case 'D':
ald_filenames[ASSET_DATA][dno] = path_join(config.game_dir, d->d_name);
ald_filenames[ASSET_DATA][dno] = path_join(config.game_dir, d_name);
ald_count[ASSET_DATA] = max(ald_count[ASSET_DATA], dno+1);
break;
default:
WARNING("Unhandled ALD file: %s", d->d_name);
WARNING("Unhandled ALD file: %s", display_utf0(d_name));
break;
}
} else if (!strcasecmp(ext, "bgi")) {
if (config.bgi_path) {
WARNING("Multiple bgi files");
continue;
goto loop_next;
}
config.bgi_path = path_join(config.game_dir, d->d_name);
config.bgi_path = path_join(config.game_dir, d_name);
} else if (!strcasecmp(ext, "wai")) {
if (config.wai_path) {
WARNING("Multiple wai files");
continue;
goto loop_next;
}
config.wai_path = path_join(config.game_dir, d->d_name);
config.wai_path = path_join(config.game_dir, d_name);
} else if (!strcasecmp(ext, "ex")) {
if (config.ex_path) {
WARNING("Multiple ex files");
continue;
goto loop_next;
}
config.ex_path = path_join(config.game_dir, d->d_name);
config.ex_path = path_join(config.game_dir, d_name);
} else if (!strcasecmp(ext, "afa")) {
const char *type = d->d_name + base_len;
const char *type = d_name + base_len;
if (!strcmp(type, "BA.afa")) {
afa_filenames[ASSET_BGM] = path_join(config.game_dir, d->d_name);
afa_filenames[ASSET_BGM] = path_join(config.game_dir, d_name);
} else if (!strcmp(type, "WA.afa") || !strcmp(type, "Sound.afa")) {
afa_filenames[ASSET_SOUND] = path_join(config.game_dir, d->d_name);
afa_filenames[ASSET_SOUND] = path_join(config.game_dir, d_name);
} else if (!strcmp(type, "Voice.afa")) {
afa_filenames[ASSET_VOICE] = path_join(config.game_dir, d->d_name);
afa_filenames[ASSET_VOICE] = path_join(config.game_dir, d_name);
} else if (!strcmp(type, "CG.afa")) {
afa_filenames[ASSET_CG] = path_join(config.game_dir, d->d_name);
afa_filenames[ASSET_CG] = path_join(config.game_dir, d_name);
} else if (!strcmp(type, "Flat.afa")) {
afa_filenames[ASSET_FLAT] = path_join(config.game_dir, d->d_name);
afa_filenames[ASSET_FLAT] = path_join(config.game_dir, d_name);
} else if (!strcmp(type, "Pact.afa")) {
afa_filenames[ASSET_PACT] = path_join(config.game_dir, d->d_name);
afa_filenames[ASSET_PACT] = path_join(config.game_dir, d_name);
}
} else if (!strcasecmp(ext, "fnl")) {
if (!config.fnl_path)
config.fnl_path = path_join(config.game_dir, d_name);
}
loop_next:
free(d_name);
}
closedir_utf8(dir);
free(base);
// open ALD archives
ald_init(ASSET_BGM, ald_filenames[ASSET_BGM], ald_count[ASSET_BGM]);
@@ -203,101 +488,4 @@ void asset_manager_init(void)
afa_init(ASSET_FLAT, afa_filenames[ASSET_FLAT]);
afa_init(ASSET_PACT, afa_filenames[ASSET_PACT]);
afa_init(ASSET_DATA, afa_filenames[ASSET_DATA]);
free(base);
closedir(dir);
}
bool asset_exists(enum asset_type type, int no)
{
return archives[type] && archive_exists(archives[type], no);
}
struct archive_data *asset_get(enum asset_type type, int no)
{
if (!archives[type])
return NULL;
return archive_get(archives[type], no);
}
static struct hash_table *cg_index = NULL;
// Convert the last sequence of digits in a string to an integer.
static int cg_name_to_int(const char *name)
{
size_t len = strlen(name);
int i;
for (i = len - 1; i >= 0 && !isdigit(name[i]); i--);
if (i < 0)
return -1;
assert(isdigit(name[i]));
for (; i > 0 && isdigit(name[i-1]); i--);
assert(isdigit(name[i]));
if (!(i = atoi(name+i)))
return -1;
return i;
}
static void add_cg_to_index(struct archive_data *data, possibly_unused void *_)
{
int logical_no = cg_name_to_int(data->name);
if (logical_no < 0) {
WARNING("Can't determine logical index for CG: %s", data->name);
return;
}
struct ht_slot *slot = ht_put_int(cg_index, logical_no, NULL);
if (slot->value)
ERROR("Duplicate CG numbers");
slot->value = (void*)(uintptr_t)(data->no + 1);
}
/*
* NOTE: Starting in Shaman's Sanctuary, .afa files are used for CGs but the
* library APIs still use integers rather than names to reference them.
* Thus it is necessary to parse file names and create an index.
*/
void asset_cg_index_init(void)
{
if (!archives[ASSET_CG])
return;
cg_index = ht_create(4096);
archive_for_each(archives[ASSET_CG], add_cg_to_index, NULL);
}
static int cg_translate_index(int no)
{
if (!cg_index)
return no;
return (uintptr_t)ht_get_int(cg_index, no, NULL);
}
struct cg *asset_cg_load(int no)
{
if (!archives[ASSET_CG])
return NULL;
if (!(no = cg_translate_index(no)))
return NULL;
return cg_load(archives[ASSET_CG], no - 1);
}
bool asset_cg_exists(int no)
{
if (!archives[ASSET_CG])
return false;
if (!(no = cg_translate_index(no)))
return false;
return true;
}
bool asset_cg_get_metrics(int no, struct cg_metrics *metrics)
{
if (!archives[ASSET_CG])
return false;
if (!(no = cg_translate_index(no)))
return NULL;
return cg_get_metrics(archives[ASSET_CG], no - 1, metrics);
}
+13 -2
View File
@@ -39,6 +39,10 @@ static int anonymous_channels[NR_ANONYMOUS_CHANNELS];
void audio_init(void)
{
static bool audio_initialized = false;
if (audio_initialized)
return;
id_pool_init(&wav);
id_pool_init(&bgm);
@@ -47,6 +51,7 @@ void audio_init(void)
}
mixer_init();
audio_initialized = true;
}
void audio_update(void)
@@ -80,8 +85,8 @@ bool audio_play_sound(int sound_no)
return false;
}
bool wav_exists(int no) { return asset_exists(ASSET_SOUND, no-1); }
bool bgm_exists(int no) { return asset_exists(ASSET_BGM, no-1); }
bool wav_exists(int no) { return asset_exists(ASSET_SOUND, no); }
bool bgm_exists(int no) { return asset_exists(ASSET_BGM, no); }
static int audio_prepare(struct id_pool *pool, int id, enum asset_type type, int no)
{
@@ -344,3 +349,9 @@ static int audio_prepare_from_archive_data(struct id_pool *pool, int id, struct
int wav_prepare_from_archive_data(int id, struct archive_data *dfile) {
return audio_prepare_from_archive_data(&wav, id, dfile);
}
int wav_get_group_num_from_data_num(int no)
{
struct wai *wai = wai_get(no);
return wai ? wai->channel : 0;
}
+5 -3
View File
@@ -18,8 +18,10 @@
#include <stdlib.h>
#include "system4.h"
#include "system4/file.h"
#include "mixer.h"
#include "little_endian.h"
#include "xsystem4.h"
#define BGI_MAX 100
@@ -44,9 +46,9 @@ static char *bgi_gets(char *buf, int n, FILE *fp)
void bgi_read(const char *path)
{
FILE *fp = fopen(path, "rb");
FILE *fp = file_open_utf8(path, "rb");
if (!fp) {
WARNING("Failed to open bgi file: %s", path);
WARNING("Failed to open bgi file: %s", display_utf0(path));
return;
}
@@ -104,7 +106,7 @@ void wai_load(const char *path)
uint8_t *file = file_read(path, &len);
if (len < 48 || file[0] != 'X' || file[1] != 'I' || file[2] != '2' || file[3] != '\0') {
WARNING("Not a .wai file: %s", path);
WARNING("Not a .wai file: %s", display_utf0(path));
goto end;
}
int count = LittleEndian_getDW(file, 8) - 1;
+99 -38
View File
@@ -29,6 +29,7 @@
#include "xsystem4.h"
#define clamp(min_value, max_value, value) min(max_value, max(min_value, value))
#define muldiv(x, y, denom) ((int64_t)(x) * (int64_t)(y) / (int64_t)(denom))
/*
* The actual mixer implementation is contained in this header.
@@ -44,7 +45,8 @@ struct fade {
atomic_bool fading;
bool stop;
uint_least32_t start_pos;
uint_least32_t end_pos;
uint_least32_t frames;
uint_least32_t elapsed;
float start_volume;
float end_volume;
};
@@ -67,8 +69,8 @@ struct channel {
// main thread read-only
atomic_uint_least32_t frame;
atomic_uint volume;
atomic_uint volume;
atomic_bool swapped;
uint_least32_t loop_start;
uint_least32_t loop_end;
@@ -143,19 +145,19 @@ static bool cb_loop(struct channel *ch)
* Callback to refill the stream's audio data.
* Called from sys_mixer_mix_audio.
*/
static int cb_read_frames(struct channel *ch, float *out, sf_count_t frame_count)
static int cb_read_frames(struct channel *ch, float *out, sf_count_t frame_count, uint_least32_t *num_read)
{
sf_count_t num_read = 0;
*num_read = 0;
// handle case where chunk crosses loop point (seamless)
// NOTE: it's assumed that the length of the loop is greater than the chunk length
if (ch->frame + frame_count >= ch->loop_end) {
// read frames up to loop_end
num_read = sf_readf_float(ch->file, out, ch->loop_end - ch->frame);
*num_read = sf_readf_float(ch->file, out, ch->loop_end - ch->frame);
// adjust parameters for later
ch->frame += num_read;
out += num_read;
frame_count -= num_read;
ch->frame += *num_read;
out += *num_read;
frame_count -= *num_read;
// seek to loop_start
if (!cb_loop(ch))
return STS_STREAM_COMPLETE;
@@ -167,10 +169,10 @@ static int cb_read_frames(struct channel *ch, float *out, sf_count_t frame_count
// read remaining data
sf_count_t n = sf_readf_float(ch->file, out, frame_count);
num_read += n;
*num_read += n;
ch->frame += n;
out += num_read;
frame_count -= num_read;
out += *num_read;
frame_count -= *num_read;
// XXX: This *shouldn't* be necessary, but sometimes libsndfile seems to stop reading
// just before the end of file (i.e. ch->frame + frame_count is < ch->info.frames,
@@ -179,7 +181,7 @@ static int cb_read_frames(struct channel *ch, float *out, sf_count_t frame_count
if (frame_count > 0) {
if (!cb_loop(ch))
return STS_STREAM_COMPLETE;
num_read += sf_readf_float(ch->file, out, frame_count);
*num_read += sf_readf_float(ch->file, out, frame_count);
}
return STS_STREAM_CONTINUE;
@@ -188,13 +190,12 @@ static int cb_read_frames(struct channel *ch, float *out, sf_count_t frame_count
/*
* Calculate the gain for a fade at a given sample.
*/
static float cb_calc_fade(struct fade *fade, uint_least32_t sample)
static float cb_calc_fade(struct fade *fade)
{
if (sample >= fade->end_pos) {
if (fade->elapsed >= fade->frames)
return fade->stop ? 0.0 : fade->end_volume;
}
float progress = (float)(sample - fade->start_pos) / (float)(fade->end_pos - fade->start_pos);
float progress = (float)fade->elapsed / (float)fade->frames;
float delta_v = fade->end_volume - fade->start_volume;
float gain = fade->start_volume + delta_v * progress;
if (gain < 0.0) return 0.0;
@@ -205,10 +206,11 @@ static float cb_calc_fade(struct fade *fade, uint_least32_t sample)
static int refill_stream(sts_mixer_sample_t *sample, void *data)
{
struct channel *ch = data;
uint_least32_t frames_read;
memset(ch->data, 0, sizeof(float) * sample->length);
// read audio data from file
int r = cb_read_frames(ch, ch->data, CHUNK_SIZE);
int r = cb_read_frames(ch, ch->data, CHUNK_SIZE, &frames_read);
// convert mono to stereo
if (ch->info.channels == 1) {
@@ -229,16 +231,21 @@ static int refill_stream(sts_mixer_sample_t *sample, void *data)
// set gain for fade
if (ch->fade.fading) {
float gain = cb_calc_fade(&ch->fade, ch->frame);
float gain = cb_calc_fade(&ch->fade);
mixers[ch->mixer_no].mixer.voices[ch->voice].gain = gain;
ch->volume = gain * 100.0;
if (ch->frame >= ch->fade.end_pos) {
ch->fade.elapsed += frames_read;
if (ch->fade.elapsed >= ch->fade.frames) {
ch->fade.fading = false;
if (ch->fade.stop) {
cb_seek(ch, 0);
r = STS_STREAM_COMPLETE;
}
}
} else {
float gain = ch->volume / 100.0;
mixers[ch->mixer_no].mixer.voices[ch->voice].gain = gain;
}
if (r == STS_STREAM_COMPLETE) {
@@ -264,8 +271,9 @@ int channel_play(struct channel *ch)
SDL_LockAudioDevice(audio_device);
if (ch->voice >= 0) {
SDL_UnlockAudioDevice(audio_device);
return 0;
return 1;
}
memset(ch->data, 0, sizeof(ch->data));
ch->voice = sts_mixer_play_stream(&mixers[ch->mixer_no].mixer, &ch->stream, 1.0f);
SDL_UnlockAudioDevice(audio_device);
return 1;
@@ -276,8 +284,9 @@ int channel_stop(struct channel *ch)
SDL_LockAudioDevice(audio_device);
if (ch->voice < 0) {
SDL_UnlockAudioDevice(audio_device);
return 0;
return 1;
}
cb_seek(ch, 0);
sts_mixer_stop_voice(&mixers[ch->mixer_no].mixer, ch->voice);
ch->voice = -1;
SDL_UnlockAudioDevice(audio_device);
@@ -320,13 +329,30 @@ int channel_set_loop_end_pos(struct channel *ch, int pos)
int channel_fade(struct channel *ch, int time, int volume, bool stop)
{
if (!time && stop)
return channel_stop(ch);
SDL_LockAudioDevice(audio_device);
ch->fade.fading = true;
ch->fade.stop = stop;
ch->fade.start_pos = ch->frame;
ch->fade.start_volume = (float)ch->volume / 100.0;
ch->fade.end_pos = ch->fade.start_pos + ((time * ch->info.samplerate) / 1000);
ch->fade.end_volume = clamp(0.0f, 1.0f, (float)volume / 100.0f);
if (!time) {
// XXX: Fade with time=0 is used to set volume. This needs to
// take effect immediately, not via the audio callback
// because the stream isn't necessarily playing yet.
// E.g. the below call sequence should fade from 0 -> 33:
//
// SACT2.Music_Fade(ch, 0, 0, 0);
// SACT2.Music_Fade(ch, 33, 4000, 0);
// SACT2.Music_Play(ch);
ch->fade.fading = false;
ch->volume = max(0, min(100, volume));
} else {
ch->fade.fading = true;
ch->fade.stop = stop;
ch->fade.start_pos = ch->frame;
ch->fade.start_volume = (float)ch->volume / 100.0;
ch->fade.frames = muldiv(time, ch->info.samplerate, 1000);
ch->fade.elapsed = 0;
ch->fade.end_volume = clamp(0.0f, 1.0f, (float)volume / 100.0f);
}
SDL_UnlockAudioDevice(audio_device);
return 1;
}
@@ -336,7 +362,7 @@ int channel_stop_fade(struct channel *ch)
SDL_LockAudioDevice(audio_device);
// XXX: we need to set the volume to end_volume and potentially stop the
// stream here; better to let the callback do it
ch->fade.end_pos = ch->frame;
ch->fade.elapsed = ch->fade.frames;
SDL_UnlockAudioDevice(audio_device);
return 1;
}
@@ -367,13 +393,13 @@ int channel_is_paused(possibly_unused struct channel *ch)
int channel_get_pos(struct channel *ch)
{
return (ch->frame * 1000) / ch->info.samplerate;
return muldiv(ch->frame, 1000, ch->info.samplerate);
}
int channel_get_length(struct channel *ch)
{
// FIXME: how is this different than channel_get_time_length?
return (ch->info.frames * 1000) / ch->info.samplerate;
return muldiv(ch->info.frames, 1000, ch->info.samplerate);
}
int channel_get_sample_pos(struct channel *ch)
@@ -390,7 +416,7 @@ int channel_seek(struct channel *ch, int pos)
{
// NOTE: SACT2.Music_Seek doesn't seem to do anything in Sengoku Rance...
SDL_LockAudioDevice(audio_device);
int r = cb_seek(ch, (pos * ch->info.samplerate) / 1000);
int r = cb_seek(ch, muldiv(pos, ch->info.samplerate, 1000));
SDL_UnlockAudioDevice(audio_device);
return r;
}
@@ -408,7 +434,7 @@ int channel_get_volume(struct channel *ch)
int channel_get_time_length(struct channel *ch)
{
return (ch->info.frames * 1000) / ch->info.samplerate;
return muldiv(ch->info.frames, 1000, ch->info.samplerate);
}
static sf_count_t channel_vio_get_filelen(void *data)
@@ -466,7 +492,7 @@ static SF_VIRTUAL_IO channel_vio = {
struct channel *channel_open(enum asset_type type, int no)
{
// get file from archive
struct archive_data *dfile = asset_get(type, no-1);
struct archive_data *dfile = asset_get(type, no);
if (!dfile) {
WARNING("Failed to load %s %d", type == ASSET_SOUND ? "WAV" : "BGM", no);
return NULL;
@@ -557,9 +583,9 @@ void mixer_init(void)
if (!config.mixer_nr_channels) {
nr_mixers = 3;
mixers = xcalloc(nr_mixers, sizeof(struct mixer));
mixers[0].name = "Music";
mixers[1].name = "Sound";
mixers[2].name = "Master";
mixers[0].name = strdup("Music");
mixers[1].name = strdup("Sound");
mixers[2].name = strdup("Master");
} else {
// NOTE: Older games don't have an explicit master channel.
// We add an extra mixer in this case for consistency.
@@ -570,10 +596,10 @@ void mixer_init(void)
nr_mixers = config.mixer_nr_channels + need_master;
mixers = xcalloc(nr_mixers, sizeof(struct mixer));
for (unsigned i = 0; i < config.mixer_nr_channels; i++) {
mixers[i].name = config.mixer_channels[i];
mixers[i].name = strdup(config.mixer_channels[i]);
}
if (need_master) {
mixers[nr_mixers-1].name = "Master";
mixers[nr_mixers-1].name = strdup("Master");
master = &mixers[nr_mixers-1];
} else {
master = &mixers[0];
@@ -647,6 +673,15 @@ const char *mixer_get_name(int n)
return mixers[n].name;
}
int mixer_set_name(int n, const char *name)
{
if (n < 0 || n >= nr_mixers)
return 0;
free(mixers[n].name);
mixers[n].name = strdup(name);
return 1;
}
int mixer_get_volume(int n, int *volume)
{
if (n < 0 || n >= nr_mixers) {
@@ -682,3 +717,29 @@ int mixer_set_mute(int n, int mute)
mixers[n].muted = !!mute;
return 1;
}
int mixer_stream_play(sts_mixer_stream_t* stream, int volume)
{
SDL_LockAudioDevice(audio_device);
float gain = clamp(0.0f, 1.0f, (float)volume / 100.0f);
int voice = sts_mixer_play_stream(&master->mixer, stream, gain);
SDL_UnlockAudioDevice(audio_device);
return voice;
}
bool mixer_stream_set_volume(int voice, int volume)
{
if (voice < 0 || voice >= STS_MIXER_VOICES)
return false;
SDL_LockAudioDevice(audio_device);
master->mixer.voices[voice].gain = clamp(0.0f, 1.0f, (float)volume / 100.0f);
SDL_UnlockAudioDevice(audio_device);
return true;
}
void mixer_stream_stop(int voice)
{
SDL_LockAudioDevice(audio_device);
sts_mixer_stop_voice(&master->mixer, voice);
SDL_UnlockAudioDevice(audio_device);
}
+72
View File
@@ -2452,6 +2452,78 @@ CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
return a;
}
/* XXX: xsystem4 addition: callback-based CreateIntArray. */
CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray_cb(int count, int (*get_number)(int,void*), void *data)
{
size_t i = 0;
cJSON *n = NULL;
cJSON *p = NULL;
cJSON *a = NULL;
if (count < 0)
{
return NULL;
}
a = cJSON_CreateArray();
for(i = 0; a && (i < (size_t)count); i++)
{
n = cJSON_CreateNumber(get_number(i, data));
if (!n)
{
cJSON_Delete(a);
return NULL;
}
if(!i)
{
a->child = n;
}
else
{
suffix_object(p, n);
}
p = n;
}
return a;
}
/* XXX: xsystem4 addition: callback-based CreateArray. */
CJSON_PUBLIC(cJSON *) cJSON_CreateArray_cb(int count, cJSON *(*get_item)(int,void*), void *data)
{
size_t i = 0;
cJSON *n = NULL;
cJSON *p = NULL;
cJSON *a = NULL;
if (count < 0)
{
return NULL;
}
a = cJSON_CreateArray();
for(i = 0; a && (i < (size_t)count); i++)
{
n = get_item(i, data);;
if (!n)
{
// XXX: NULL return is ignored
continue;
}
if(!i)
{
a->child = n;
}
else
{
suffix_object(p, n);
}
p = n;
}
return a;
}
CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
{
size_t i = 0;
+1 -1
View File
@@ -72,7 +72,7 @@ sexp sexp_get_page_stub (sexp ctx, sexp self, sexp_sint_t n, sexp arg0) {
sexp sexp_backtrace_stub (sexp ctx, sexp self, sexp_sint_t n) {
sexp res;
res = ((print_stack_trace()), SEXP_VOID);
res = ((dbg_print_stack_trace()), SEXP_VOID);
return res;
}
+1 -1
View File
@@ -82,7 +82,7 @@
(int varno variable-varno)
(vm_value value variable-vm-value))
(define-c void (backtrace print_stack_trace) ())
(define-c void (backtrace dbg_print_stack_trace) ())
(define-c (maybe-null page) (get-page get_page) (int))
(define-c (maybe-null page) (frame-page frame_page) (int))
+1067
View File
File diff suppressed because it is too large Load Diff
+516
View File
@@ -0,0 +1,516 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#define VM_PRIVATE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <ctype.h>
#include <limits.h>
#include <assert.h>
#include "system4.h"
#include "system4/file.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "vm.h"
#include "vm/heap.h"
#include "vm/page.h"
#include "scene.h"
#include "debugger.h"
#include "little_endian.h"
#include "xsystem4.h"
struct dbg_cmd_node;
static bool stepping = false;
struct dbg_cmd_list {
unsigned nr_commands;
struct dbg_cmd_node *commands;
};
struct dbg_cmd_node {
enum { CMD_NODE_CMD, CMD_NODE_MOD } type;
union {
struct dbg_cmd cmd;
struct {
const char *name;
struct dbg_cmd_list list;
} mod;
};
};
static void dbg_cmd_help(unsigned nr_args, char **args);
static void dbg_cmd_backtrace(unsigned nr_args, char **args)
{
dbg_print_stack_trace();
}
static void dbg_cmd_breakpoint(unsigned nr_args, char **args)
{
int addr = strtol(args[0], NULL, 0);
if (addr > 0) {
dbg_set_address_breakpoint(addr, NULL, NULL);
} else {
dbg_set_function_breakpoint(args[0], NULL, NULL);
}
}
static void dbg_cmd_continue(unsigned nr_args, char **args)
{
stepping = false;
dbg_continue();
}
static void dbg_cmd_frame(unsigned nr_args, char **args)
{
int frame_no = atoi(args[0]);
if (frame_no < 0 || frame_no >= call_stack_ptr) {
DBG_ERROR("Invalid frame number: %d", frame_no);
return;
}
dbg_current_frame = frame_no;
dbg_print_frame(frame_no);
}
static void dbg_cmd_locals(unsigned nr_args, char **args)
{
int frame_no = nr_args > 0 ? atoi(args[0]) : dbg_current_frame;
if (frame_no < 0 || frame_no >= call_stack_ptr) {
DBG_ERROR("Invalid frame number: %d", frame_no);
return;
}
struct page *page = heap_get_page(call_stack[call_stack_ptr - (frame_no+1)].page_slot);
struct ain_function *f = &ain->functions[page->index];
for (int i = 0; i < f->nr_vars; i++) {
struct string *value = dbg_value_to_string(&f->vars[i].type, page->values[i], 1);
printf("[%d] %s: %s\n", i, display_sjis0(f->vars[i].name), display_sjis1(value->text));
free_string(value);
}
}
static void log_handler(struct breakpoint *bp)
{
struct ain_function *f = bp->data;
struct page *locals = local_page();
printf("%s(", display_sjis0(f->name));
for (int i = 0; i < f->nr_args; i++) {
struct string *value = dbg_value_to_string(&f->vars[i].type, locals->values[i], 1);
printf(i > 0 ? ", %s" : "%s", display_sjis0(value->text));
free_string(value);
}
printf(")\n");
}
static void dbg_cmd_log(unsigned nr_args, char **args)
{
int fno = ain_get_function(ain, args[0]);
if (fno < 0) {
DBG_ERROR("No function with name '%s'", args[0]);
return;
}
dbg_set_function_breakpoint(args[0], log_handler, &ain->functions[fno]);
}
static void dbg_cmd_members(unsigned nr_args, char **args)
{
int frame_no = nr_args > 0 ? atoi(args[0]) : dbg_current_frame;
if (frame_no < 0 || frame_no >= call_stack_ptr) {
DBG_ERROR("Invalid frame number: %d", frame_no);
return;
}
struct page *page = get_struct_page(frame_no);
if (!page) {
DBG_ERROR("Frame #%d is not a method", frame_no);
return;
}
assert(page->type == STRUCT_PAGE);
assert(page->index >= 0 && page->index < ain->nr_structures);
struct ain_struct *s = &ain->structures[page->index];
assert(page->nr_vars == s->nr_members);
for (int i = 0; i < s->nr_members; i++) {
struct string *value = dbg_value_to_string(&s->members[i].type, page->values[i], 1);
printf("[%d] %s: %s\n", i, display_sjis0(s->members[i].name), display_sjis1(value->text));
free_string(value);
}
}
static void dbg_cmd_print(unsigned nr_args, char **args)
{
int recursive = nr_args == 2 ? atoi(args[1]) : 2;
struct ain_type type;
union vm_value value = dbg_eval_string(args[0], &type);
if (type.data == AIN_VOID)
return;
struct string *str = dbg_value_to_string(&type, value, recursive);
printf("%s\n", display_sjis0(str->text));
free_string(str);
}
static void dbg_cmd_quit(unsigned nr_args, char **args)
{
dbg_quit();
}
static void dbg_cmd_scene(unsigned nr_args, char **args)
{
scene_print();
}
static void dbg_cmd_next(unsigned nr_args, char **args)
{
if (!dbg_set_step_over_breakpoint()) {
DBG_ERROR("Can't step over this instruction");
return;
}
stepping = true;
dbg_continue();
}
static void dbg_cmd_step(unsigned nr_args, char **args)
{
if (!dbg_set_step_into_breakpoint()) {
DBG_ERROR("Can't step into this instruction");
return;
}
stepping = true;
dbg_continue();
}
static void dbg_cmd_finish(unsigned nr_args, char **args)
{
if (!dbg_set_finish_breakpoint()) {
DBG_ERROR("Can't set finish breakpoint from this location");
return;
}
stepping = true;
dbg_continue();
}
#ifdef HAVE_SCHEME
static void dbg_cmd_scheme(unsigned nr_args, char **args)
{
dbg_scm_repl();
}
#endif
static void dbg_cmd_vm_state(unsigned nr_args, char **args)
{
dbg_print_vm_state();
}
static struct dbg_cmd dbg_default_commands[] = {
{ "backtrace", "bt", NULL, "Display stack trace", 0, 0, dbg_cmd_backtrace },
{ "breakpoint", "bp", "<function-or-address>", "Set breakpoint at a function or address", 1, 1, dbg_cmd_breakpoint },
{ "continue", "c", NULL, "Resume execution", 0, 0, dbg_cmd_continue },
{ "finish", "fin", NULL, "Execute until the current function returns", 0, 0, dbg_cmd_finish },
{ "frame", "f", "<frame-number>", "Set the current frame", 1, 1, dbg_cmd_frame },
{ "help", "h", "[command-name]", "Get help about a command", 0, 2, dbg_cmd_help },
{ "locals", "l", "[frame-number]", "Print local variables", 0, 1, dbg_cmd_locals },
{ "log", NULL, "<function-name>", "Log function calls", 1, 1, dbg_cmd_log },
{ "members", "m", "[frame-number]", "Print struct members", 0, 1, dbg_cmd_members },
{ "next", "n", NULL, "Step to the next instruction within the current function", 0, 0, dbg_cmd_next },
{ "print", "p", "<variable-name> [recursion-depth]", "Print a variable", 1, 2, dbg_cmd_print },
{ "quit", "q", NULL, "Quit xsystem4", 0, 0, dbg_cmd_quit },
{ "scene", NULL, NULL, "Display scene graph", 0, 0, dbg_cmd_scene },
{ "step", "s", NULL, "Step to the next instruction", 0, 0, dbg_cmd_step },
#ifdef HAVE_SCHEME
{ "scheme", "scm", NULL, "Drop into the Scheme REPL", 0, 0, dbg_cmd_scheme },
#endif
{ "vm-state", "vm", NULL, "Display current VM state", 0, 0, dbg_cmd_vm_state },
};
static struct dbg_cmd_list dbg_commands = {0};
/*
* Get a command by name.
*/
static struct dbg_cmd_node *dbg_get_node(struct dbg_cmd_list *list, const char *name)
{
for (unsigned i = 0; i < list->nr_commands; i++) {
switch (list->commands[i].type) {
case CMD_NODE_CMD: {
struct dbg_cmd *cmd = &list->commands[i].cmd;
if (!strcmp(name, cmd->fullname) || (cmd->shortname && !strcmp(name, cmd->shortname)))
return &list->commands[i];
break;
}
case CMD_NODE_MOD:
if (!strcmp(name, list->commands[i].mod.name))
return &list->commands[i];
break;
}
}
return NULL;
}
static void dbg_help_cmd(struct dbg_cmd *cmd)
{
printf("%s", cmd->fullname);
if (cmd->shortname)
printf(", %s", cmd->shortname);
if (cmd->arg_description)
printf(" %s", cmd->arg_description);
printf("\n\t%s\n", cmd->description);
}
static int cmd_name_max(struct dbg_cmd_list *list)
{
int m = 0;
for (unsigned i = 0; i < list->nr_commands; i++) {
if (list->commands[i].type == CMD_NODE_MOD) {
m = max(m, strlen(list->commands[i].mod.name));
} else if (list->commands[i].type == CMD_NODE_CMD) {
m = max(m, strlen(list->commands[i].cmd.fullname));
}
}
return m;
}
static void dbg_help_cmd_short(struct dbg_cmd *cmd, int name_len)
{
printf("%*s", name_len, cmd->fullname);
if (cmd->shortname)
printf(" (%s)%*s", cmd->shortname, 3 - (int)strlen(cmd->shortname), "");
else
printf(" ");
printf(" -- %s\n", cmd->description);
}
static void dbg_help_list(struct dbg_cmd_list *list)
{
int name_len = cmd_name_max(list);
puts("");
puts("Available Commands");
puts("==================");
for (unsigned i = 0; i < list->nr_commands; i++) {
if (list->commands[i].type == CMD_NODE_MOD) {
printf("%s - command module; run to see additional commands\n",
list->commands[i].mod.name);
} else if (list->commands[i].type == CMD_NODE_CMD) {
dbg_help_cmd_short(&list->commands[i].cmd, name_len);
}
}
puts("");
puts("Type 'help <command>' to get help about a specific command.");
}
static void dbg_cmd_help(unsigned nr_args, char **args)
{
if (!nr_args) {
dbg_help_list(&dbg_commands);
return;
}
struct dbg_cmd_node *node = dbg_get_node(&dbg_commands, args[0]);
if (!node) {
DBG_ERROR("'%s' is not a command or module", args[0]);
return;
}
if (nr_args > 1) {
if (node->type != CMD_NODE_MOD) {
DBG_ERROR("'%s' is not a command module", args[0]);
return;
}
node = dbg_get_node(&node->mod.list, args[1]);
if (!node) {
DBG_ERROR("'%s %s' is not a command or module", args[0], args[1]);
return;
}
}
switch (node->type) {
case CMD_NODE_CMD:
dbg_help_cmd(&node->cmd);
break;
case CMD_NODE_MOD:
dbg_help_list(&node->mod.list);
break;
}
}
void dbg_cmd_add_module(const char *name, unsigned nr_commands, struct dbg_cmd *commands)
{
dbg_commands.commands = xrealloc_array(dbg_commands.commands, dbg_commands.nr_commands,
dbg_commands.nr_commands+1, sizeof(struct dbg_cmd_node));
struct dbg_cmd_node *node = &dbg_commands.commands[dbg_commands.nr_commands++];
node->type = CMD_NODE_MOD;
node->mod.name = name;
node->mod.list.nr_commands = nr_commands;
node->mod.list.commands = xcalloc(nr_commands, sizeof(struct dbg_cmd_node));
for (unsigned i = 0; i < nr_commands; i++) {
node->mod.list.commands[i].type = CMD_NODE_CMD;
node->mod.list.commands[i].cmd = commands[i];
}
}
#ifdef HAVE_READLINE
#include <readline/readline.h>
#include <readline/history.h>
/*
* Get a string from the user. The result can be modified but shouldn't be free'd.
*/
static char *cmd_gets(void)
{
static char *line_read = NULL;
free(line_read);
line_read = readline("dbg(cmd)> ");
if (line_read && *line_read)
add_history(line_read);
return line_read;
}
#else
/*
* Get a string from the user. The result can be modified but shouldn't be free'd.
*/
static char *cmd_gets(void)
{
static char line[1024];
printf("dbg(cmd)> ");
fflush(stdout);
fgets(line, 1024, stdin);
return line;
}
#endif
/*
* Parse a line into an array of words. Modified the input string.
*/
static char **cmd_parse(char *line, unsigned *nr_words)
{
static char *words[32];
*nr_words = 0;
while (*line) {
// skip whitespace
while (*line && isspace(*line)) line++;
if (!*line) break;
// save word ptr
words[(*nr_words)++] = line;
// skip word
while (*line && !isspace(*line)) line++;
if (!*line) break;
*line = '\0';
line++;
}
return words;
}
static void execute_command(struct dbg_cmd *cmd, unsigned nr_args, char **args)
{
if (nr_args < cmd->min_args || nr_args > cmd->max_args) {
printf("Wrong number of arguments to '%s' command\n", cmd->fullname);
return;
}
cmd->run(nr_args, args);
}
static void execute_words(struct dbg_cmd_list *list, unsigned nr_words, char **words)
{
struct dbg_cmd_node *node = dbg_get_node(list, words[0]);
if (!node) {
printf("Invalid command: %s (type 'help' for a list of commands)\n", words[0]);
return;
}
switch (node->type) {
case CMD_NODE_CMD:
execute_command(&node->cmd, nr_words-1, words+1);
break;
case CMD_NODE_MOD:
if (nr_words == 1) {
printf("TODO: module help");
return;
}
execute_words(&node->mod.list, nr_words-1, words+1);
break;
}
}
static void execute_line(char *line)
{
unsigned nr_words;
char **words = cmd_parse(line, &nr_words);
if (!nr_words)
return;
execute_words(&dbg_commands, nr_words, words);
}
void dbg_cmd_repl(void)
{
if (stepping)
dbg_print_vm_state();
else
puts("Entering the debugger REPL. Type 'help' for a list of commands.");
while (1) {
char *line = cmd_gets();
if (line)
execute_line(line);
}
}
static void execute_config(void *_f)
{
FILE *f = _f;
char line[1024];
while (fgets(line, 1024, f)) {
execute_line(line);
}
}
static void read_config(const char *path)
{
FILE *f = file_open_utf8(path, "rb");
if (!f)
return;
dbg_start(execute_config, f);
fclose(f);
}
void dbg_cmd_init(void)
{
dbg_commands.nr_commands = sizeof(dbg_default_commands)/sizeof(*dbg_default_commands);
dbg_commands.commands = xcalloc(dbg_commands.nr_commands, sizeof(struct dbg_cmd_node));
for (unsigned i = 0; i < dbg_commands.nr_commands; i++) {
dbg_commands.commands[i].type = CMD_NODE_CMD;
dbg_commands.commands[i].cmd = dbg_default_commands[i];
}
char *path = xmalloc(PATH_MAX);
snprintf(path, PATH_MAX, "%s/.xsys4-debugrc", config.home_dir);
read_config(path);
free(path);
path = gamedir_path(".xsys4-debugrc");
read_config(path);
free(path);
}
+42 -91
View File
@@ -20,6 +20,8 @@
#include <assert.h>
#include <chibi/eval.h>
#include "system4/ain.h"
#include "system4/file.h"
#include "system4/instructions.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
@@ -30,10 +32,6 @@
#include "debugger.h"
#include "little_endian.h"
#define SCM_ERROR(fmt, ...) sys_warning("ERROR: " fmt "\n", ##__VA_ARGS__)
bool dbg_enabled = true;
struct variable {
enum ain_data_type data_type;
int struct_type;
@@ -130,85 +128,53 @@ static struct variable *page_ref(struct page *page, int i)
return v;
}
struct breakpoint {
enum opcode restore_op;
sexp handler;
char *message;
int count;
};
static struct breakpoint *breakpoints = NULL;
static unsigned nr_breakpoints = 0;
static sexp dbg_ctx;
static void set_function_breakpoint(const char *_name, sexp handler)
static void set_parameter(const char *param, sexp value)
{
if (!sexp_procedurep(handler) && handler != SEXP_FALSE) {
SCM_ERROR("Breakpoint handler must be a procedure or #f");
sexp_eval(dbg_ctx, sexp_list2(dbg_ctx, sexp_intern(dbg_ctx, param, -1), value), NULL);
}
static void dbg_scm_breakpoint_handler(struct breakpoint *bp)
{
set_parameter("breakpoint-count", sexp_make_integer(dbg_ctx, bp->count++));
// TODO: breakpoint-function parameter with function name, argument count, etc.
if ((sexp)bp->data == SEXP_FALSE) {
NOTICE("%s", bp->message);
dbg_scm_repl();
} else {
sexp_apply(dbg_ctx, (sexp)bp->data, SEXP_NULL);
}
}
static void set_function_breakpoint(const char *name, sexp handler)
{
if (handler == SEXP_FALSE) {
dbg_set_function_breakpoint(name, NULL, NULL);
return;
}
char *name = utf2sjis(_name, 0);
int fno = ain_get_function(ain, name);
free(name);
if (fno < 0) {
SCM_ERROR("No function with name '%s'", _name);
if (!sexp_procedurep(handler)) {
DBG_ERROR("Breakpoint handler must be a procedure or #f");
return;
}
struct ain_function *f = &ain->functions[fno];
breakpoints = xrealloc_array(breakpoints, nr_breakpoints, nr_breakpoints+1, sizeof(struct breakpoint));
breakpoints[nr_breakpoints].restore_op = LittleEndian_getW(ain->code, f->address);
breakpoints[nr_breakpoints].handler = handler;
if (handler != SEXP_FALSE)
if (dbg_set_function_breakpoint(name, dbg_scm_breakpoint_handler, handler)) {
sexp_preserve_object(dbg_ctx, handler);
breakpoints[nr_breakpoints].message = xmalloc(512);
snprintf(breakpoints[nr_breakpoints].message, 511, "Hit breakpoint at function '%s' (0x%08x)", _name, f->address);
LittleEndian_putW(ain->code, f->address, BREAKPOINT + nr_breakpoints);
nr_breakpoints++;
}
}
static void set_address_breakpoint(uint32_t address, sexp handler)
{
if (!sexp_procedurep(handler) && handler != SEXP_FALSE) {
SCM_ERROR("Breakpoint handler must be a procedure or #f");
if (handler == SEXP_FALSE) {
dbg_set_address_breakpoint(address, NULL, NULL);
return;
}
if (address & 1 || address >= ain->code_size - 2) {
SCM_ERROR("Invalid instruction address: 0x%08x", address);
if (!sexp_procedurep(handler)) {
DBG_ERROR("Breakpoint handler must be a procedure or #f");
return;
}
// XXX: this is not very robust; some illegal addresses will slip through
// if the data looks like a valid opcode
enum opcode op = LittleEndian_getW(ain->code, address);
if (op < 0 || op >= NR_OPCODES) {
SCM_ERROR("Invalid instruction address: 0x%08x", address);
return;
}
breakpoints = xrealloc_array(breakpoints, nr_breakpoints, nr_breakpoints+1, sizeof(struct breakpoint));
breakpoints[nr_breakpoints].restore_op = op;
breakpoints[nr_breakpoints].handler = handler;
if (handler != SEXP_FALSE)
if (dbg_set_address_breakpoint(address, dbg_scm_breakpoint_handler, handler)) {
sexp_preserve_object(dbg_ctx, handler);
breakpoints[nr_breakpoints].message = xmalloc(512);
snprintf(breakpoints[nr_breakpoints].message, 511, "Hit breakpoint at 0x%08x", address);
LittleEndian_putW(ain->code, address, BREAKPOINT + nr_breakpoints);
nr_breakpoints++;
}
static void print_stack_trace(void)
{
for (int i = call_stack_ptr - 1, j = 0; i >= 0; i--, j++) {
struct ain_function *f = &ain->functions[call_stack[i].fno];
char *u = sjis2utf(f->name, strlen(f->name));
uint32_t addr = (i == call_stack_ptr - 1) ? instr_ptr : call_stack[i+1].call_address;
NOTICE("#%d 0x%08x in %s", j, addr, u);
free(u);
}
}
@@ -226,7 +192,7 @@ static struct page *frame_page(int i)
// autogenerated with `chibi-ffi src/debug-ffi.stub`
#include "debug-ffi.c"
void dbg_init(void)
void dbg_scm_init(void)
{
if (!dbg_enabled)
return;
@@ -236,44 +202,29 @@ void dbg_init(void)
sexp_init_library(dbg_ctx, NULL, 0, sexp_context_env(dbg_ctx), sexp_version, SEXP_ABI_IDENTIFIER);
sexp_eval_string(dbg_ctx, "(import (scheme base))", -1, NULL);
sexp_eval_string(dbg_ctx, "(import (chibi repl))", -1, NULL);
sexp_eval_string(dbg_ctx, "(define *prompt* (make-parameter \"dbg> \"))", -1, NULL);
sexp_eval_string(dbg_ctx, "(define *prompt* (make-parameter \"dbg(scm)> \"))", -1, NULL);
sexp_eval_string(dbg_ctx, "(define breakpoint-count (make-parameter 0))", -1, NULL);
sexp_eval_string(dbg_ctx, "(define (repl-make-prompt m) (*prompt*))", -1, NULL);
sexp_eval_string(dbg_ctx, "(load \"./debugger.scm\")", -1, NULL);
if (file_exists("./debugger.scm"))
sexp_eval_string(dbg_ctx, "(load \"./debugger.scm\")", -1, NULL);
else
sexp_eval_string(dbg_ctx, "(load \"" XSYS4_DATA_DIR "/debugger.scm\")", -1, NULL);
}
void dbg_fini(void)
void dbg_scm_fini(void)
{
if (!dbg_enabled)
return;
sexp_destroy_context(dbg_ctx);
}
void dbg_repl(void)
void dbg_scm_repl(void)
{
if (!dbg_enabled)
return;
NOTICE("Entering the Scheme debugger REPL. Type '\\exit' to exit.");
sexp_eval_string(dbg_ctx, "(repl 'escape: #\\\\ 'make-prompt: repl-make-prompt)", -1, NULL);
}
static void set_parameter(const char *param, sexp value)
{
sexp_eval(dbg_ctx, sexp_list2(dbg_ctx, sexp_intern(dbg_ctx, param, -1), value), NULL);
}
enum opcode dbg_handle_breakpoint(unsigned bp_no)
{
assert(bp_no < nr_breakpoints);
set_parameter("breakpoint-count", sexp_make_integer(dbg_ctx, breakpoints[bp_no].count++));
// TODO: breakpoint-function parameter with function name, argument count, etc.
if (breakpoints[bp_no].handler == SEXP_FALSE) {
NOTICE("%s", breakpoints[bp_no].message);
dbg_repl();
} else {
sexp_apply(dbg_ctx, breakpoints[bp_no].handler, SEXP_NULL);
}
return breakpoints[bp_no].restore_op;
}
+345 -5
View File
@@ -34,6 +34,7 @@ struct copy_shader {
// optional
GLint color;
GLint threshold;
GLint threshold2;
};
struct copy_data {
@@ -43,6 +44,7 @@ struct copy_data {
// optional
float r, g, b, a;
float threshold;
float threshold2;
};
#define ROTATE_DATA(dst, _sx, _sy, _w, _h) \
@@ -63,12 +65,17 @@ static struct copy_shader copy_alpha_key_shader;
static struct copy_shader copy_use_amap_under_shader;
static struct copy_shader copy_use_amap_border_shader;
static struct copy_shader blend_amap_color_shader;
static struct copy_shader blend_amap_alpha_shader;
static struct copy_shader blend_amap_alpha_bright_shader;
static struct copy_shader blend_use_amap_color_shader;
static struct copy_shader fill_shader;
static struct copy_shader fill_amap_over_border_shader;
static struct copy_shader fill_amap_under_border_shader;
static struct copy_shader fill_amap_gradation_ud_shader;
static struct copy_shader hitbox_shader;
static struct copy_shader hitbox_noblend_shader;
static struct copy_shader amap_saturate_shader;
static struct copy_shader blend_rmap_color_shader;
static struct copy_shader dilate_shader;
static void prepare_copy_shader(struct gfx_render_job *job, void *data)
{
@@ -79,6 +86,7 @@ static void prepare_copy_shader(struct gfx_render_job *job, void *data)
glUniform4f(s->color, d->r, d->g, d->b, d->a);
glUniform1f(s->threshold, d->threshold);
glUniform1f(s->threshold2, d->threshold2);
}
static void load_copy_shader(struct copy_shader *s, const char *v_path, const char *f_path)
@@ -88,6 +96,7 @@ static void load_copy_shader(struct copy_shader *s, const char *v_path, const ch
s->top_right = glGetUniformLocation(s->s.program, "top_right");
s->color = glGetUniformLocation(s->s.program, "color");
s->threshold = glGetUniformLocation(s->s.program, "threshold");
s->threshold2 = glGetUniformLocation(s->s.program, "threshold2");
s->s.prepare = prepare_copy_shader;
}
@@ -115,8 +124,10 @@ void gfx_draw_init(void)
// copy shader that sets source RGB to a constant
load_copy_shader(&blend_amap_color_shader, "shaders/render.v.glsl", "shaders/blend_amap_color.f.glsl");
// copy shader that multiples the source alpha by a constant
load_copy_shader(&blend_amap_alpha_shader, "shaders/render.v.glsl", "shaders/blend_amap_alpha.f.glsl");
// copy shader that multiples the source color and alpha by a constant
load_copy_shader(&blend_amap_alpha_bright_shader, "shaders/render.v.glsl", "shaders/blend_amap_alpha_bright.f.glsl");
load_copy_shader(&blend_use_amap_color_shader, "shaders/render.v.glsl", "shaders/blend_use_amap_color.f.glsl");
// basic fill shader
load_copy_shader(&fill_shader, "shaders/render.v.glsl", "shaders/fill.f.glsl");
@@ -127,11 +138,23 @@ void gfx_draw_init(void)
// fill shader that only fills fragments below a certain alpha threshold
load_copy_shader(&fill_amap_under_border_shader, "shaders/render.v.glsl", "shaders/fill_amap_under_border.f.glsl");
// fill shader that fills the alpha map with a gradient
load_copy_shader(&fill_amap_gradation_ud_shader, "shaders/render.v.glsl", "shaders/fill_amap_gradation_ud.f.glsl");
// shader that discards texels that fail a hitbox test
load_copy_shader(&hitbox_shader, "shaders/render.v.glsl", "shaders/hitbox.f.glsl");
// hitbox shader which ignores alpha component of texture (a=1)
load_copy_shader(&hitbox_noblend_shader, "shaders/render.v.glsl", "shaders/hitbox_noblend.f.glsl");
// shader that sets the color to black or white depending on alpha value
load_copy_shader(&amap_saturate_shader, "shaders/render.v.glsl", "shaders/amap_saturate.f.glsl");
// shader that sets source RGB to a constant, using source red channel as alpha
load_copy_shader(&blend_rmap_color_shader, "shaders/render.v.glsl", "shaders/blend_rmap_color.f.glsl");
// shader that dilates every pixel (for bold/outline text rendering)
load_copy_shader(&dilate_shader, "shaders/render.v.glsl", "shaders/dilate.f.glsl");
}
static void run_draw_shader(Shader *s, Texture *dst, Texture *src, mat4 mw_transform, mat4 wv_transform, struct copy_data *data)
@@ -306,6 +329,29 @@ void gfx_blend(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w
restore_blend_mode();
}
void gfx_blend_src_bright(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int a, int rate)
{
GLfloat f_rate = rate / 255.0;
f_rate *= (a / 255.0);
glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_ALPHA, GL_ZERO, GL_ONE);
glBlendColor(f_rate, f_rate, f_rate, a / 255.0);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_copy_shader(&copy_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_add_satur(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_copy_shader(&copy_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_amap(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -316,6 +362,16 @@ void gfx_blend_amap(Texture *dst, int dx, int dy, Texture *src, int sx, int sy,
restore_blend_mode();
}
void gfx_blend_amap_src_only(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_copy_shader(&copy_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_amap_color(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int r, int g, int b)
{
// color = (r,g,b) * src_alpha + dst_color * (1 - src_alpha)
@@ -326,6 +382,21 @@ void gfx_blend_amap_color(Texture *dst, int dx, int dy, Texture *src, int sx, in
data.r = r / 255.0;
data.g = g / 255.0;
data.b = b / 255.0;
data.a = 1.0;
run_copy_shader(&blend_amap_color_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_amap_color_alpha(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int r, int g, int b, int a)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
data.r = r / 255.0;
data.g = g / 255.0;
data.b = b / 255.0;
data.a = a / 255.0;
run_copy_shader(&blend_amap_color_shader.s, dst, src, &data);
restore_blend_mode();
@@ -336,8 +407,89 @@ void gfx_blend_amap_alpha(Texture *dst, int dx, int dy, Texture *src, int sx, in
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
data.threshold = a / 255.0;
run_copy_shader(&blend_amap_alpha_shader.s, dst, src, &data);
data.r = 1.0;
data.g = 1.0;
data.b = 1.0;
data.a = a / 255.0;
run_copy_shader(&blend_amap_alpha_bright_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_amap_bright(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int rate)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
data.r = rate / 255.0;
data.g = rate / 255.0;
data.b = rate / 255.0;
data.a = 1.0;
run_copy_shader(&blend_amap_alpha_bright_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_amap_alpha_src_bright(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int alpha, int rate)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
data.r = rate / 255.0;
data.g = rate / 255.0;
data.b = rate / 255.0;
data.a = alpha / 255.0;
run_copy_shader(&blend_amap_alpha_bright_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_use_amap_color(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int r, int g, int b, int rate)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
data.r = r / 255.0;
data.g = g / 255.0;
data.b = b / 255.0;
data.a = 1.0;
data.threshold = rate / 255.0;
run_copy_shader(&blend_use_amap_color_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_screen(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_copy_shader(&copy_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_multiply(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_copy_shader(&copy_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_blend_screen_alpha(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h, int a)
{
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
data.r = a / 255.0;
data.g = a / 255.0;
data.b = a / 255.0;
data.a = 1.0;
run_copy_shader(&blend_amap_alpha_bright_shader.s, dst, src, &data);
restore_blend_mode();
}
@@ -405,6 +557,66 @@ void gfx_fill_amap_under_border(Texture *dst, int x, int y, int w, int h, int al
restore_blend_mode();
}
void gfx_fill_amap_gradation_ud(Texture *dst, int x, int y, int w, int h, int up_a, int down_a)
{
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO);
struct copy_data data = COPY_DATA(x, y, 0, 0, w, h);
data.threshold = up_a / 255.0;
data.threshold2 = down_a / 255.0;
run_fill_shader(&fill_amap_gradation_ud_shader.s, dst, &data);
restore_blend_mode();
}
void gfx_fill_screen(Texture *dst, int x, int y, int w, int h, int r, int g, int b)
{
glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(x, y, 0, 0, w, h);
data.r = r / 255.0;
data.g = g / 255.0;
data.b = b / 255.0;
data.a = 1.0;
run_copy_shader(&fill_shader.s, dst, NULL, &data);
restore_blend_mode();
}
void gfx_fill_multiply(Texture *dst, int x, int y, int w, int h, int r, int g, int b)
{
glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(x, y, 0, 0, w, h);
data.r = r / 255.0;
data.g = g / 255.0;
data.b = b / 255.0;
data.a = 1.0;
run_copy_shader(&fill_shader.s, dst, NULL, &data);
restore_blend_mode();
}
void gfx_satur_dp_dpxsa(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_copy_shader(&amap_saturate_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_screen_da_daxsa(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ONE);
struct copy_data data = COPY_DATA(dx, dy, sx, sy, w, h);
run_copy_shader(&copy_shader.s, dst, src, &data);
restore_blend_mode();
}
void gfx_add_da_daxsa(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
// color = dst_color
@@ -442,6 +654,18 @@ void gfx_sub_da_daxsa(struct texture *dst, int dx, int dy, struct texture *src,
restore_blend_mode();
}
void gfx_bright_dest_only(Texture *dst, int x, int y, int w, int h, int rate)
{
GLfloat f_rate = rate / 255.0;
glBlendFuncSeparate(GL_ZERO, GL_CONSTANT_COLOR, GL_ZERO, GL_ONE);
glBlendColor(f_rate, f_rate, f_rate, 1.0);
struct copy_data data = COPY_DATA(x, y, 0, 0, w, h);
run_copy_shader(&copy_shader.s, dst, NULL, &data);
restore_blend_mode();
}
// FIXME: DrawGraph.dll does some really strange clipping on the src/dst rectangles
// before drawing. This implementation does what you would normally expect
// a stretch function to do when passed negative (x,y) coordinates.
@@ -488,6 +712,20 @@ void gfx_copy_stretch_blend_amap(struct texture *dst, int dx, int dy, int dw, in
restore_blend_mode();
}
void gfx_copy_stretch_blend_amap_alpha(struct texture *dst, int dx, int dy, int dw, int dh, struct texture *src, int sx, int sy, int sw, int sh, int a)
{
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
struct copy_data data = STRETCH_DATA(dx, dy, dw, dh, sx, sy, sw, sh);
data.r = 1.0;
data.g = 1.0;
data.b = 1.0;
data.a = a / 255.0;
run_copy_shader(&blend_amap_alpha_bright_shader.s, dst, src, &data);
restore_blend_mode();
}
// FIXME: this doesn't work correctly when the src rectangle crosses the edge of the CG.
static void copy_rot_zoom(Texture *dst, Texture *src, int sx, int sy, int w, int h, float rotate, float mag, Shader *shader)
{
@@ -565,6 +803,45 @@ void gfx_copy_rotate_y_use_amap(Texture *dst, Texture *front, Texture *back, int
copy_rotate_y(dst, front, back, sx, sy, w, h, rot, mag, &hitbox_shader.s);
}
static void copy_rotate_x(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag, Shader *shader)
{
Texture *src = front;
float flip_y = 1.0;
rot = 360.0 - rot;
if (rot > 90.0 && rot <= 270.0) {
src = back;
flip_y = -1.0;
}
gfx_fill_amap(dst, 0, 0, dst->w, dst->h, 0);
mat4 mw_transform = GLM_MAT4_IDENTITY_INIT;
glm_rotate_x(mw_transform, rot * (M_PI/180.0), mw_transform);
glm_scale(mw_transform, (vec3){ src->w * mag, src->h * mag * flip_y, 0 });
glm_translate(mw_transform, (vec3){ -0.5, -0.5, 0});
mat4 proj_transform;
float fov = 22.5 * (M_PI / 180.0);
// calculate the camera distance such that the height at the pivot is unchanged
float cam_off = ((float)dst->h * 0.5) / tanf(fov * 0.5);
glm_perspective(fov, (float)dst->w / dst->h, 0.1, cam_off + w * mag, proj_transform);
glm_translate(proj_transform, (vec3){ 0, 0, -cam_off });
struct copy_data data = ROTATE_DATA(dst, sx, sy, w, h);
run_draw_shader(shader, dst, src, mw_transform, proj_transform, &data);
}
void gfx_copy_rotate_x(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag)
{
copy_rotate_x(dst, front, back, sx, sy, w, h, rot, mag, &hitbox_noblend_shader.s);
}
void gfx_copy_rotate_x_use_amap(Texture *dst, Texture *front, Texture *back, int sx, int sy, int w, int h, float rot, float mag)
{
copy_rotate_x(dst, front, back, sx, sy, w, h, rot, mag, &hitbox_shader.s);
}
void gfx_copy_reverse_LR(Texture *dst, int dx, int dy, Texture *src, int sx, int sy, int w, int h)
{
mat4 mw_transform = MAT4(
@@ -728,3 +1005,66 @@ void gfx_copy_stretch_with_alpha_map(Texture *dst, int dx, int dy, int dw, int d
restore_blend_mode();
}
// XXX: Not an actual DrawGraph function; used for rendering text
void gfx_draw_glyph(Texture *dst, float dx, int dy, Texture *glyph, SDL_Color color, float scale_x, float bold_width)
{
dx = roundf(dx);
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ZERO, GL_ONE);
struct copy_data fill_data = COPY_DATA(dx, dy, dx, dy, glyph->w * scale_x, glyph->h);
fill_data.r = color.r / 255.0;
fill_data.g = color.g / 255.0;
fill_data.b = color.b / 255.0;
fill_data.a = 0.0;
fill_data.threshold = 0.001;
run_copy_shader(&fill_amap_under_border_shader.s, dst, dst, &fill_data);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
struct copy_data data = STRETCH_DATA(
dx, dy, glyph->w * scale_x, glyph->h,
0, 0, glyph->w, glyph->h);
data.r = color.r / 255.0;
data.g = color.g / 255.0;
data.b = color.b / 255.0;
data.a = 1.0;
if (bold_width < 0.01) {
run_copy_shader(&blend_rmap_color_shader.s, dst, glyph, &data);
} else {
data.threshold = bold_width;
run_copy_shader(&dilate_shader.s, dst, glyph, &data);
}
restore_blend_mode();
}
void gfx_draw_glyph_to_pmap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, SDL_Color color, float scale_x)
{
struct copy_data data = STRETCH_DATA(
dx, dy, glyph_pos.w * scale_x, glyph_pos.h,
glyph_pos.x, glyph_pos.y, glyph_pos.w, glyph_pos.h);
data.r = color.r / 255.0;
data.g = color.g / 255.0;
data.b = color.b / 255.0;
data.a = 1.0;
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
run_copy_shader(&blend_rmap_color_shader.s, dst, glyph, &data);
restore_blend_mode();
}
void gfx_draw_glyph_to_amap(Texture *dst, float dx, int dy, Texture *glyph, Rectangle glyph_pos, float scale_x)
{
struct copy_data data = STRETCH_DATA(
dx, dy, glyph_pos.w * scale_x, glyph_pos.h,
glyph_pos.x, glyph_pos.y, glyph_pos.w, glyph_pos.h);
data.r = 1.0;
data.g = 1.0;
data.b = 1.0;
data.a = 1.0;
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO);
run_copy_shader(&blend_rmap_color_shader.s, dst, glyph, &data);
restore_blend_mode();
}
+20 -8
View File
@@ -45,9 +45,14 @@
#define M_PI (3.14159265358979323846)
#endif
static void dungeon_render(struct sact_sprite *sp);
struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version, int surface)
{
struct dungeon_context *ctx = xcalloc(1, sizeof(struct dungeon_context));
ctx->plugin.name = "DrawDungeon";
ctx->plugin.update = dungeon_render;
ctx->plugin.debug_print = NULL;
ctx->version = version;
ctx->surface = surface;
struct sact_sprite *sp = sact_get_sprite(ctx->surface);
@@ -56,6 +61,7 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version
// Dungeon scene will be rendered to this texture.
struct texture *texture = sprite_get_texture(sp);
sprite_bind_plugin(sp, &ctx->plugin);
glGenRenderbuffers(1, &ctx->depth_buffer);
glBindRenderbuffer(GL_RENDERBUFFER, ctx->depth_buffer);
@@ -68,6 +74,10 @@ struct dungeon_context *dungeon_context_create(enum draw_dungeon_version version
void dungeon_context_free(struct dungeon_context *ctx)
{
struct sact_sprite *sp = sact_try_get_sprite(ctx->surface);
if (sp)
sprite_bind_plugin(sp, NULL);
if (ctx->dgn)
dgn_free(ctx->dgn);
if (ctx->dtx)
@@ -89,11 +99,11 @@ static GLuint *load_event_textures(int *nr_textures_out)
{
char *path = gamedir_path("Data/Event.alk");
int error = ARCHIVE_SUCCESS;
struct alk_archive *alk = alk_open(path, ARCHIVE_MMAP, &error);
struct alk_archive *alk = alk_open(path, MMAP_IF_64BIT, &error);
if (error == ARCHIVE_FILE_ERROR) {
WARNING("alk_open(\"%s\"): %s", path, strerror(errno));
WARNING("alk_open(\"%s\"): %s", display_utf0(path), strerror(errno));
} else if (error == ARCHIVE_BAD_ARCHIVE_ERROR) {
WARNING("alk_open(\"%s\"): invalid .alk file", path);
WARNING("alk_open(\"%s\"): invalid .alk file", display_utf0(path));
}
free(path);
if (!alk)
@@ -136,11 +146,11 @@ bool dungeon_load(struct dungeon_context *ctx, int num)
if (ctx->version == DRAW_DUNGEON_1) {
char *path = gamedir_path("Data/DungeonData.dlf");
int error = ARCHIVE_SUCCESS;
struct archive *dlf = (struct archive *)dlf_open(path, ARCHIVE_MMAP, &error);
struct archive *dlf = (struct archive *)dlf_open(path, MMAP_IF_64BIT, &error);
if (error == ARCHIVE_FILE_ERROR) {
WARNING("dlf_open(\"%s\"): %s", path, strerror(errno));
WARNING("dlf_open(\"%s\"): %s", display_utf0(path), strerror(errno));
} else if (error == ARCHIVE_BAD_ARCHIVE_ERROR) {
WARNING("dlf_open(\"%s\"): invalid .dlf file", path);
WARNING("dlf_open(\"%s\"): invalid .dlf file", display_utf0(path));
}
free(path);
if (!dlf)
@@ -248,9 +258,11 @@ static void model_view_matrix(struct camera *camera, mat4 out)
glm_lookat(eye, camera->pos, up, out);
}
void dungeon_render(struct dungeon_context *ctx)
static void dungeon_render(struct sact_sprite *sp)
{
struct sact_sprite *sp = sact_get_sprite(ctx->surface);
struct dungeon_context *ctx = (struct dungeon_context *)sp->plugin;
if (!ctx->loaded || !ctx->draw_enabled)
return;
sprite_dirty(sp);
struct texture *texture = sprite_get_texture(sp);
+164 -54
View File
@@ -14,6 +14,8 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <math.h>
#include <SDL.h>
#include "effect.h"
#include "gfx/gfx.h"
@@ -65,7 +67,7 @@ const char *effect_names[NR_EFFECTS] = {
[EFFECT_VERTICAL_BAR_BLUR_HD] = "EFFECT_VERTICAL_BAR_BLUR_HD",
[EFFECT_AMAP_CROSSFADE2] = "EFFECT_AMAP_CROSSFADE2",
[EFFECT_ZOOM_LR] = "EFFECT_ZOOM_LR",
[EFFECT_ZOOR_RL] = "EFFECT_ZOOR_RL",
[EFFECT_ZOOM_RL] = "EFFECT_ZOOM_RL",
[EFFECT_CROSSFADE_LR] = "EFFECT_CROSSFADE_LR",
[EFFECT_CROSSFADE_RL] = "EFFECT_CROSSFADE_RL",
[EFFECT_PIXEL_EXPLOSION] = "EFFECT_PIXEL_EXPLOSION",
@@ -129,65 +131,148 @@ static void render_effect_shader(struct effect_shader *shader, Texture *old, Tex
#define EFFECT_SHADER(path) { .s = { .prepare = prepare_effect_shader }, .f_path = path}
static struct effect_shader crossfade_shader = EFFECT_SHADER("shaders/effects/crossfade.f.glsl");
static struct effect_shader crossfade_lr_shader = EFFECT_SHADER("shaders/effects/crossfade_lr.f.glsl");
static struct effect_shader crossfade_up_down_shader = EFFECT_SHADER("shaders/effects/crossfade_up_down.f.glsl");
static struct effect_shader mosaic_shader = EFFECT_SHADER("shaders/effects/mosaic.f.glsl");
static struct effect_shader blind_down_shader = EFFECT_SHADER("shaders/effects/blind_down.f.glsl");
static struct effect_shader blind_lr_shader = EFFECT_SHADER("shaders/effects/blind_lr.f.glsl");
static struct effect_shader linear_blur_shader = EFFECT_SHADER("shaders/effects/linear_blur.f.glsl");
static struct effect_shader zigzag_crossfade_shader = EFFECT_SHADER("shaders/effects/zigzag_crossfade.f.glsl");
static struct effect_shader noise_crossfade_shader = EFFECT_SHADER("shaders/effects/noise_crossfade.f.glsl");
static struct effect_shader turn_page_shader = EFFECT_SHADER("shaders/effects/turn_page.f.glsl");
static struct effect_shader sepia_noise_crossfade_shader = EFFECT_SHADER("shaders/effects/sepia_noise_crossfade.f.glsl");
static struct effect_shader blur_fadeout_shader = EFFECT_SHADER("shaders/effects/blur_fadeout.f.glsl");
static struct effect_shader blur_crossfade_shader = EFFECT_SHADER("shaders/effects/blur_crossfade.f.glsl");
extern GLuint main_surface_fb;
static struct effect_shader *effect_shaders[NR_EFFECTS] = {
[EFFECT_CROSSFADE] = &crossfade_shader,
[EFFECT_CROSSFADE_LR] = &crossfade_lr_shader,
[EFFECT_UP_DOWN_CROSSFADE] = &crossfade_up_down_shader,
[EFFECT_CROSSFADE_MOSAIC] = &mosaic_shader,
[EFFECT_BLIND_DOWN] = &blind_down_shader,
[EFFECT_BLIND_LR] = &blind_lr_shader,
[EFFECT_LINEAR_BLUR] = &linear_blur_shader,
[EFFECT_ZIGZAG_CROSSFADE] = &zigzag_crossfade_shader,
[EFFECT_NOISE_CROSSFADE] = &noise_crossfade_shader,
[EFFECT_TURN_PAGE] = &turn_page_shader,
[EFFECT_SEPIA_NOISE_CROSSFADE] = &sepia_noise_crossfade_shader,
[EFFECT_BLUR_FADEOUT] = &blur_fadeout_shader,
[EFFECT_BLUR_CROSSFADE] = &blur_crossfade_shader,
};
int sact_Effect(int type, possibly_unused int time, possibly_unused int key)
{
if (type <= 0 || type >= NR_EFFECTS) {
WARNING("Invalid or unknown effect: %d", type);
return 0;
}
struct effect_shader *s = effect_shaders[type];
if (!s) {
WARNING("Unimplemented effect: %s", effect_names[type]);
return 0;
}
// load shader lazily
if (!s->s.program) {
load_effect_shader(s);
}
// get old & new scene textures
Texture old, new;
gfx_copy_main_surface(&old);
scene_render();
gfx_copy_main_surface(&new);
//effect_callback effect = effects[type];
for (int i = 0; i < time; i += 16) {
gfx_clear();
render_effect_shader(s, &old, &new, (float)i / (float)time);
gfx_swap();
SDL_Delay(16);
}
gfx_delete_texture(&old);
gfx_delete_texture(&new);
return 1;
}
static struct {
bool on;
int type;
Texture old;
Texture new;
} trans = {0};
} effect = {0};
static void effect_fadeout(float rate)
{
gfx_copy_bright(gfx_main_surface(), 0, 0, &effect.old, 0, 0,
effect.old.w, effect.old.h, (1.0f - rate) * 255);
}
static void effect_fadein(float rate)
{
gfx_copy_bright(gfx_main_surface(), 0, 0, &effect.new, 0, 0,
effect.new.w, effect.new.h, rate * 255);
}
static void effect_whiteout(float rate)
{
Texture *dst = gfx_main_surface();
gfx_fill(dst, 0, 0, dst->w, dst->h, 255, 255, 255);
gfx_blend(dst, 0, 0, &effect.old, 0, 0, dst->w, dst->h, (1.0f - rate) * 255);
}
static void effect_whitein(float rate)
{
Texture *dst = gfx_main_surface();
gfx_fill(dst, 0, 0, dst->w, dst->h, 255, 255, 255);
gfx_blend(dst, 0, 0, &effect.new, 0, 0, dst->w, dst->h, rate * 255);
}
static void effect_zoom_lr(float rate)
{
Texture *dst = gfx_main_surface();
unsigned x_pos = roundf(dst->w * rate);
gfx_copy_stretch(dst, x_pos, 0, dst->w-x_pos, dst->h, &effect.old, 0, 0, effect.old.w, effect.old.h);
gfx_copy_stretch(dst, 0, 0, x_pos, dst->h, &effect.new, 0, 0, effect.new.w, effect.new.h);
}
static void effect_zoom_rl(float rate)
{
Texture *dst = gfx_main_surface();
unsigned x_pos = dst->w - roundf(dst->w * rate);
gfx_copy_stretch(dst, x_pos, 0, dst->w-x_pos, dst->h, &effect.new, 0, 0, effect.new.w, effect.new.h);
gfx_copy_stretch(dst, 0, 0, x_pos, dst->h, &effect.old, 0, 0, effect.old.w, effect.old.h);
}
static void effect_oscillate(float rate)
{
Texture *dst = gfx_main_surface();
int delta_x = (rand() % (dst->w / 10) - (dst->w / 20)) * (1.0f - rate);
int delta_y = (rand() % (dst->h / 10) - (dst->h / 20)) * (1.0f - rate);;
gfx_copy(dst, 0, 0, &effect.old, 0, 0, dst->w, dst->h);
gfx_copy(dst, delta_x, delta_y, &effect.new, 0, 0, dst->w, dst->h);
}
static void effect_tv_switch(float rate, Texture *src)
{
Texture *dst = gfx_main_surface();
if (rate < 0.5f) {
int h = max(1, (int)(dst->h * (1.0f - rate * 2.0f)));
gfx_copy_stretch(dst, 0, dst->h * rate, dst->w, h,
src, 0, 0, src->w, src->h);
} else {
rate -= 0.5f;
int w = dst->w * (1.0f - rate * 2.0f);
gfx_copy_stretch(dst, dst->w * rate, dst->h / 2, w, 1,
src, 0, 0, src->w, src->h);
}
}
static void effect_tv_switch_off(float rate)
{
effect_tv_switch(rate, &effect.old);
}
static void effect_tv_switch_on(float rate)
{
effect_tv_switch(1.0f - rate, &effect.new);
}
static void effect_zoom_in_crossfade(float rate)
{
Texture *dst = gfx_main_surface();
float scale = 1.0f + powf(rate, 4.0f) * 16.0f;
int w = roundf(dst->w * scale);
int h = roundf(dst->h * scale);
int x = -((w - dst->w)/2);
int y = -((h - dst->h)/2);
int a = (1.0f - rate) * 255;
gfx_copy(dst, 0, 0, &effect.new, 0, 0, dst->w, dst->h);
gfx_copy_stretch_blend(dst, x, y, w, h, &effect.old, 0, 0, dst->w, dst->h, a);
}
typedef void (*effect_fun)(float rate);
static effect_fun effect_functions[NR_EFFECTS] = {
[EFFECT_FADEOUT] = effect_fadeout,
[EFFECT_FADEIN] = effect_fadein,
[EFFECT_WHITEOUT] = effect_whiteout,
[EFFECT_WHITEIN] = effect_whitein,
[EFFECT_OSCILLATE] = effect_oscillate,
[EFFECT_TV_SWITCH_OFF] = effect_tv_switch_off,
[EFFECT_TV_SWITCH_ON] = effect_tv_switch_on,
[EFFECT_ZOOM_LR] = effect_zoom_lr,
[EFFECT_ZOOM_RL] = effect_zoom_rl,
[EFFECT_ZOOM_IN_CROSSFADE] = effect_zoom_in_crossfade,
};
int sact_TRANS_Begin(int type)
{
@@ -195,39 +280,64 @@ int sact_TRANS_Begin(int type)
WARNING("Invalid or unknown effect: %d", type);
return 0;
}
struct effect_shader *s = effect_shaders[type];
if (!s) {
WARNING("Unimplemented effect: %s", effect_names[type]);
return 0;
if (effect_functions[type]) {
// nothing to do
}
// load shader lazily
if (!s->s.program) {
load_effect_shader(s);
else {
struct effect_shader *s = effect_shaders[type];
if (!s) {
WARNING("Unimplemented effect: %s", effect_names[type]);
type = EFFECT_BLUR_CROSSFADE;
s = effect_shaders[type];
}
// load shader lazily
if (!s->s.program) {
load_effect_shader(s);
}
}
trans.on = true;
trans.type = type;
gfx_copy_main_surface(&trans.old);
effect.on = true;
effect.type = type;
gfx_copy_main_surface(&effect.old);
scene_render();
gfx_copy_main_surface(&trans.new);
gfx_copy_main_surface(&effect.new);
return 1;
}
int sact_TRANS_Update(float rate)
{
if (!trans.on) {
if (!effect.on) {
return 0;
}
gfx_clear();
render_effect_shader(effect_shaders[trans.type], &trans.old, &trans.new, rate);
if (effect_functions[effect.type]) {
effect_functions[effect.type](rate);
} else {
render_effect_shader(effect_shaders[effect.type], &effect.old, &effect.new, rate);
}
gfx_swap();
return 1;
}
int sact_TRANS_End(void)
{
trans.on = false;
gfx_delete_texture(&trans.old);
gfx_delete_texture(&trans.new);
effect.on = false;
gfx_delete_texture(&effect.old);
gfx_delete_texture(&effect.new);
return 1;
}
int sact_Effect(int type, possibly_unused int time, possibly_unused int key)
{
if (!sact_TRANS_Begin(type))
return 0;
for (int i = 0; i < time; i+= 16) {
sact_TRANS_Update((float)i / (float)time);
SDL_Delay(16);
}
sact_TRANS_End();
return 1;
}
+78 -27
View File
@@ -24,6 +24,7 @@
#include "vm.h"
#include "vm/heap.h"
#include "vm/page.h"
#include "xsystem4.h"
#define HLL_MAX_ARGS 64
@@ -57,6 +58,7 @@ bool library_function_exists(int libno, int fno)
static void trace_hll_call(struct ain_library *lib, struct ain_hll_function *f,
struct hll_function *fun, union vm_value *r, void *_args)
{
/*
// list of traced libraries
if (!strcmp(lib->name, "StoatSpriteEngine") || !strcmp(lib->name, "ChipmunkSpriteEngine")) {
// list of excluded functions
@@ -86,21 +88,25 @@ static void trace_hll_call(struct ain_library *lib, struct ain_hll_function *f,
}
//else if (!strcmp(lib->name, "DrawGraph"));
else if (!strcmp(lib->name, "SACT2")) {
if (strncmp(f->name, "SP_", 3)) goto notrace;
if (!strcmp(f->name, "Key_IsDown")) goto notrace;
if (!strcmp(f->name, "Mouse_GetPos")) goto notrace;
if (!strcmp(f->name, "SP_ExistAlpha")) goto notrace;
if (!strcmp(f->name, "SP_IsPtInRect")) goto notrace;
if (!strcmp(f->name, "SP_IsPtIn")) goto notrace;
if (!strcmp(f->name, "SP_IsUsing")) goto notrace;
if (!strcmp(f->name, "SP_SetShow")) goto notrace;
if (!strcmp(f->name, "SP_SetPos")) goto notrace;
if (!strcmp(f->name, "Timer_Get")) goto notrace;
if (!strcmp(f->name, "Update")) goto notrace;
}
else if (!strcmp(lib->name, "SengokuRanceFont"));
else*/ if (!strcmp(lib->name, "SengokuRanceFont")) {
if (!strcmp(f->name, "SP_SetReduceDescender")) goto notrace;
if (!strcmp(f->name, "SP_ClearState")) goto notrace;
}
else goto notrace;
char *u = sjis2utf(ain->functions[call_stack[call_stack_ptr-1].fno].name, 0);
sys_message("(%s) ", u);
free(u);
sys_message("(%s) ", display_sjis0(ain->functions[call_stack[call_stack_ptr-1].fno].name));
sys_message("%s.%s(", lib->name, f->name);
union vm_value **args = _args;
@@ -108,7 +114,7 @@ static void trace_hll_call(struct ain_library *lib, struct ain_hll_function *f,
if (i > 0) {
sys_message(", ");
}
sys_message("%s=", f->arguments[i].name);
sys_message("%s=", display_sjis0(f->arguments[i].name));
switch (f->arguments[i].type.data) {
case AIN_INT:
case AIN_LONG_INT:
@@ -120,9 +126,7 @@ static void trace_hll_call(struct ain_library *lib, struct ain_hll_function *f,
case AIN_STRING: {
struct string ***strs = _args;
struct string *s = *strs[i];
char *u = sjis2utf(s->text, s->size);
sys_message("\"%s\"", u);
free(u);
sys_message("\"%s\"", display_sjis0(s->text));
break;
}
case AIN_BOOL:
@@ -156,7 +160,7 @@ static void trace_hll_call(struct ain_library *lib, struct ain_hll_function *f,
sys_message(" -> %f", r->f);
break;
case AIN_STRING:
sys_message(" -> \"%s\"", ((struct string*)r->ref)->text);
sys_message(" -> \"%s\"", display_sjis0(((struct string*)r->ref)->text));
break;
case AIN_BOOL:
sys_message(" -> %s", r->i ? "true" : "false");
@@ -169,10 +173,10 @@ static void trace_hll_call(struct ain_library *lib, struct ain_hll_function *f,
union vm_value ***args = _args;
switch (f->arguments[i].type.data) {
case AIN_REF_INT:
sys_message(" (%s=%d)", f->arguments[i].name, (*args[i])->i);
sys_message(" (%s=%d)", display_sjis0(f->arguments[i].name), (*args[i])->i);
break;
case AIN_REF_FLOAT:
sys_message(" (%s=%f)", f->arguments[i].name, (*args[i])->f);
sys_message(" (%s=%f)", display_sjis0(f->arguments[i].name), (*args[i])->f);
break;
default:
break;
@@ -294,31 +298,43 @@ extern struct static_library lib_AliceLogo5;
extern struct static_library lib_AnteaterADVEngine;
extern struct static_library lib_BanMisc;
extern struct static_library lib_Bitarray;
extern struct static_library lib_CGManager;
extern struct static_library lib_ChipmunkSpriteEngine;
extern struct static_library lib_ChrLoader;
extern struct static_library lib_CommonSystemData;
extern struct static_library lib_Confirm;
extern struct static_library lib_Confirm2;
extern struct static_library lib_Confirm3;
extern struct static_library lib_CrayfishLogViewer;
extern struct static_library lib_Cursor;
extern struct static_library lib_Data;
extern struct static_library lib_DataFile;
extern struct static_library lib_DrawDungeon;
extern struct static_library lib_DrawDungeon14;
extern struct static_library lib_DrawGraph;
extern struct static_library lib_DrawMovie;
extern struct static_library lib_DrawMovie2;
extern struct static_library lib_DrawPluginManager;
extern struct static_library lib_DrawSimpleText;
extern struct static_library lib_File;
extern struct static_library lib_File2;
extern struct static_library lib_FileOperation;
extern struct static_library lib_FillAngle;
extern struct static_library lib_GoatGUIEngine;
extern struct static_library lib_Gpx2Plus;
extern struct static_library lib_GUIEngine;
extern struct static_library lib_IbisInputEngine;
extern struct static_library lib_InputDevice;
extern struct static_library lib_InputString;
extern struct static_library lib_KiwiSoundEngine;
extern struct static_library lib_LoadCG;
extern struct static_library lib_MainEXFile;
extern struct static_library lib_MainSurface;
extern struct static_library lib_MarmotModelEngine;
extern struct static_library lib_Math;
extern struct static_library lib_MapLoader;
extern struct static_library lib_MenuMsg;
extern struct static_library lib_MonsterInfo;
extern struct static_library lib_MsgLogManager;
extern struct static_library lib_MsgLogViewer;
extern struct static_library lib_MsgSkip;
@@ -326,14 +342,17 @@ extern struct static_library lib_OutputLog;
extern struct static_library lib_PassRegister;
extern struct static_library lib_PlayDemo;
extern struct static_library lib_PlayMovie;
extern struct static_library lib_ReignEngine;
extern struct static_library lib_SACT2;
extern struct static_library lib_SACTDX;
extern struct static_library lib_SengokuRanceFont;
extern struct static_library lib_SoundFilePlayer;
extern struct static_library lib_StoatSpriteEngine;
extern struct static_library lib_StretchHelper;
extern struct static_library lib_SystemService;
extern struct static_library lib_SystemServiceEx;
extern struct static_library lib_Timer;
extern struct static_library lib_Toushin3Loader;
extern struct static_library lib_VSFile;
static struct static_library *static_libraries[] = {
@@ -347,31 +366,43 @@ static struct static_library *static_libraries[] = {
&lib_AnteaterADVEngine,
&lib_BanMisc,
&lib_Bitarray,
&lib_CGManager,
&lib_ChipmunkSpriteEngine,
&lib_ChrLoader,
&lib_CommonSystemData,
&lib_Confirm,
&lib_Confirm2,
&lib_Confirm3,
&lib_CrayfishLogViewer,
&lib_Cursor,
&lib_Data,
&lib_DataFile,
&lib_DrawDungeon,
&lib_DrawDungeon14,
&lib_DrawGraph,
&lib_DrawMovie,
&lib_DrawMovie2,
&lib_DrawPluginManager,
&lib_DrawSimpleText,
&lib_File,
&lib_File2,
&lib_FileOperation,
&lib_FillAngle,
&lib_GoatGUIEngine,
&lib_Gpx2Plus,
&lib_GUIEngine,
&lib_IbisInputEngine,
&lib_InputDevice,
&lib_InputString,
&lib_KiwiSoundEngine,
&lib_LoadCG,
&lib_MainEXFile,
&lib_MainSurface,
&lib_MarmotModelEngine,
&lib_Math,
&lib_MapLoader,
&lib_MenuMsg,
&lib_MonsterInfo,
&lib_MsgLogManager,
&lib_MsgLogViewer,
&lib_MsgSkip,
@@ -379,14 +410,17 @@ static struct static_library *static_libraries[] = {
&lib_PassRegister,
&lib_PlayDemo,
&lib_PlayMovie,
&lib_ReignEngine,
&lib_SACT2,
&lib_SACTDX,
&lib_SengokuRanceFont,
&lib_SoundFilePlayer,
&lib_StoatSpriteEngine,
&lib_StretchHelper,
&lib_SystemService,
&lib_SystemServiceEx,
&lib_Timer,
&lib_Toushin3Loader,
&lib_VSFile,
NULL
};
@@ -451,16 +485,32 @@ static struct hll_function *link_static_library(struct ain_library *ainlib, stru
ERROR("Too many arguments to library function: %s", ainlib->functions[i].name);
}
return dst;
}
static void library_run(struct static_library *lib, const char *name)
{
for (int i = 0; lib->functions[i].name; i++) {
if (!strcmp(lib->functions[i].name, "_ModuleInit")) {
if (!strcmp(lib->functions[i].name, name)) {
((void(*)(void))lib->functions[i].fun)();
break;
}
}
return dst;
}
void link_libraries(void)
static void library_run_all(const char *name)
{
for (int i = 0; i < ain->nr_libraries; i++) {
for (int j = 0; static_libraries[j]; j++) {
if (!strcmp(ain->libraries[i].name, static_libraries[j]->name)) {
library_run(static_libraries[j], name);
break;
}
}
}
}
static void link_libraries(void)
{
if (libraries)
return;
@@ -479,24 +529,25 @@ void link_libraries(void)
}
}
void library_fini(struct static_library *lib)
void init_libraries(void)
{
for (int i = 0; lib->functions[i].name; i++) {
if (!strcmp(lib->functions[i].name, "_ModuleFini")) {
((void(*)(void))lib->functions[i].fun)();
break;
}
}
library_run_all("_PreLink");
link_libraries();
library_run_all("_ModuleInit");
}
void exit_libraries(void)
{
for (int i = 0; i < ain->nr_libraries; i++) {
for (int j = 0; static_libraries[j]; j++) {
if (!strcmp(ain->libraries[i].name, static_libraries[j]->name)) {
library_fini(static_libraries[j]);
break;
}
library_run_all("_ModuleFini");
}
void static_library_replace(struct static_library *lib, const char *name, void *fun)
{
for (int i = 0; lib->functions[i].name; i++) {
if (!strcmp(lib->functions[i].name, name)) {
lib->functions[i].fun = fun;
return;
}
}
ERROR("No library function '%s.%s'", lib->name, name);
}
-153
View File
@@ -1,153 +0,0 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include "gfx/gfx.h"
#include "gfx/types.h"
#include "system4.h"
#include "system4/fnl.h"
#include "system4/utfsjis.h"
#include "gfx/gfx.h"
static void set_pixel(uint8_t *p, int w, int h, int x, int y, SDL_Color c)
{
if (x >= w || y >= h)
return;
p[y*w*4 + x*4 + 0] = c.r;
p[y*w*4 + x*4 + 1] = c.g;
p[y*w*4 + x*4 + 2] = c.b;
p[y*w*4 + x*4 + 3] = 255;
}
static void render_outline(struct text_style *ts, uint8_t *surf, uint8_t *data, unsigned long data_size, int x, int w, int h)
{
const int span = w * 4;
const int glyph_w = (data_size*8) / h;
const int size = ts->font_size->denominator * ts->edge_width;
uint32_t p = 0;
for (int row = h - 1; row >= 0; row--) {
uint8_t *pos = surf + row*span + x*4;
for (int col = 0; col < glyph_w; col++, p++, pos += 4) {
bool on = data[p/8] & (1 << (7 - p % 8));
if (!on)
continue;
int start_x = x + col - size;
int start_y = row - size;
for (int ol_row = 0; ol_row < size*2; ol_row++) {
for (int ol_col = 0; ol_col < size*2; ol_col++) {
set_pixel(surf, w, h, start_x + ol_col, start_y + ol_row, ts->edge_color);
}
}
}
}
}
// TODO: cache glyph textures, render directly to dst texture
static void render_glyph(struct fnl_font_face *font, struct text_style *ts, uint8_t *surf, struct fnl_glyph *glyph, int x, int w, int h)
{
unsigned long data_size;
uint8_t *data = fnl_glyph_data(font->font->fnl, glyph, &data_size);
const int span = w * 4;
const int glyph_w = (data_size*8) / h;
if (ts->edge_width)
render_outline(ts, surf, data, data_size, x, w, h);
uint32_t p = 0;
for (int row = h - 1; row >= 0; row--) {
uint8_t *pos = surf + row*span + x*4;
for (int col = 0; col < glyph_w; col++, p++) {
bool on = data[p/8] & (1 << (7 - p % 8));
if (on) {
set_pixel(surf, w, h, x+col, row, ts->color);
}
pos += 4;
}
}
free(data);
}
static void render_text(struct fnl_font_face *font, struct text_style *ts, Texture *dst, char *text)
{
// create array of fnl_glyph
const int height = font->height;
int len = sjis_count_char(text);
struct fnl_glyph **glyphs = xcalloc(len, sizeof(struct fnl_glyph*));
for (int i = 0; i < len; i++) {
glyphs[i] = fnl_get_glyph(font, sjis_code(text));
text = sjis_skip_char(text);
}
// calculate width/height of text surface
int width = 0;
for (int i = 0; i < len; i++) {
width += glyphs[i]->real_width;
}
// allocate memory for surface
uint8_t *surf = xcalloc(4, width * height);
// render glyphs to surface
int x = 0;
for (int i = 0; i < len; i++) {
render_glyph(font, ts, surf, glyphs[i], x, width, height);
x += glyphs[i]->real_width;
}
// create texture from surface
gfx_init_texture_with_pixels(dst, width, height, surf);
free(surf);
free(glyphs);
}
static void draw_text(Texture *dst, Texture *glyph, int x, int y, float scale)
{
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, dst, x, y, glyph->w, glyph->h);
mat4 mw_transform = MAT4(
glyph->w * scale, 0, 0, 0,
0, glyph->h * scale, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
mat4 wv_transform = WV_TRANSFORM(glyph->w, glyph->h);
struct gfx_render_job job = {
.texture = glyph->handle,
.world_transform = mw_transform[0],
.view_transform = wv_transform[0],
.data = glyph
};
gfx_render(&job);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
}
int fnl_draw_text(struct fnl *fnl, struct text_style *ts, Texture *dst, int x, int y, char *text)
{
Texture rendered;
struct fnl_font_face *font = &fnl->fonts[ts->font_type].faces[ts->font_size->face];
render_text(font, ts, &rendered, text);
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE);
draw_text(dst, &rendered, x, y, 1.0 / ts->font_size->denominator);
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
int w = rendered.w / (float)ts->font_size->denominator;
gfx_delete_texture(&rendered);
return w;
}
+235
View File
@@ -0,0 +1,235 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include "system4.h"
#include "system4/fnl.h"
#include "system4/hashtable.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "gfx/gfx.h"
#include "gfx/font.h"
#include "xsystem4.h"
struct fnl_bitmap_glyph {
unsigned width;
unsigned height;
unsigned advance;
uint8_t *pixels;
};
struct fnl_bitmap_size {
struct fnl_font_face *face;
unsigned nr_glyphs;
struct fnl_bitmap_glyph **glyphs;
};
struct fnl_font_size {
struct font_size super;
struct fnl_bitmap_size *bitmap_size;
unsigned denominator;
};
struct font_fnl {
struct font super;
struct fnl_font *font;
unsigned nr_bitmap_sizes;
struct fnl_bitmap_size *bitmap_sizes;
unsigned nr_sizes;
struct fnl_font_size *sizes;
};
static struct font_size *fnl_font_get_size(struct font *_font, float size)
{
struct font_fnl *font = (struct font_fnl*)_font;
float min_diff = 9999;
struct fnl_font_size *closest = &font->sizes[0];
for (unsigned i = 0; i < font->nr_sizes; i++) {
float diff = fabsf(font->sizes[i].super.size - size);
if (diff < min_diff) {
min_diff = diff;
closest = &font->sizes[i];
}
}
return &closest->super;
}
static struct font_size *fnl_font_get_size_round_down(struct font *_font, float size)
{
struct font_fnl *font = (struct font_fnl*)_font;
float min_diff = 9999;
struct fnl_font_size *closest = &font->sizes[0];
for (unsigned i = 0; i < font->nr_sizes; i++) {
if (font->sizes[i].super.size > size)
continue;
float diff = fabsf(font->sizes[i].super.size - size);
if (diff < min_diff) {
min_diff = diff;
closest = &font->sizes[i];
}
}
return &closest->super;
}
static float fnl_font_get_actual_size(struct font *font, float size)
{
return fnl_font_get_size(font, size)->size;
}
static float fnl_font_get_actual_size_round_down(struct font *font, float size)
{
return fnl_font_get_size_round_down(font, size)->size;
}
static struct fnl_bitmap_glyph *fnl_get_bitmap_glyph(struct fnl_bitmap_size *bitmap, unsigned index)
{
if (bitmap->glyphs[index])
return bitmap->glyphs[index];
unsigned long data_size;
uint8_t *data = fnl_glyph_data(bitmap->face->font->fnl, &bitmap->face->glyphs[index], &data_size);
const int glyph_w = (data_size*8) / bitmap->face->height;
const int glyph_h = bitmap->face->height;
struct fnl_bitmap_glyph *out = xmalloc(sizeof(struct fnl_bitmap_glyph));
out->width = glyph_w;
out->height = glyph_h;
out->advance = bitmap->face->glyphs[index].real_width;
out->pixels = xmalloc(glyph_w * glyph_h);
// expand 1-bit bitmap to 8-bit
for (unsigned i = 0; i < glyph_w * glyph_h; i++) {
unsigned row = (glyph_h - 1) - i / glyph_w;
unsigned col = i % glyph_w;
bool on = data[i/8] & (1 << (7 - i % 8));
out->pixels[row*glyph_w + col] = on ? 255 : 0;
}
free(data);
bitmap->glyphs[index] = out;
return out;
}
#define GLYPH_BORDER_SIZE 4
static bool fnl_font_get_glyph(struct font_size *_size, struct glyph *glyph, uint32_t code, enum font_weight weight)
{
struct fnl_font_size *size = (struct fnl_font_size*)_size;
unsigned index = fnl_char_to_index(code);
if (index > size->bitmap_size->nr_glyphs)
return false;
if (!size->bitmap_size->face->glyphs[index].data_pos)
return false;
struct fnl_bitmap_glyph *fullsize = fnl_get_bitmap_glyph(size->bitmap_size, index);
const unsigned block_width = fullsize->width / size->denominator;
const unsigned block_height = fullsize->height / size->denominator;
const unsigned width = block_width + GLYPH_BORDER_SIZE*2;
const unsigned height = block_height + GLYPH_BORDER_SIZE*2;
const unsigned off_x = GLYPH_BORDER_SIZE;
const unsigned off_y = GLYPH_BORDER_SIZE;
// Sample each pixel in size->denominator`-sized blocks and compute the average.
// TODO: no need to sample every pixel; 4 should be fine?
uint8_t *pixels = xcalloc(1, width * height);
unsigned *acc = xcalloc(block_width * block_height, sizeof(unsigned));
for (unsigned i = 0; i < block_width * block_height; i++) {
unsigned dst_row = i / block_width;
unsigned dst_col = i % block_width;
for (unsigned r = 0; r < size->denominator; r++) {
unsigned src_row = dst_row * size->denominator + r;
for (unsigned c = 0; c < size->denominator; c++) {
unsigned src_col = dst_col * size->denominator + c;
acc[i] += fullsize->pixels[src_row*fullsize->width + src_col];
}
}
uint8_t p = acc[i] / (size->denominator * size->denominator);
pixels[(dst_row+off_y)*width + (dst_col+off_x)] = p;
}
gfx_init_texture_rmap(&glyph->t[weight], width, height, pixels);
glyph->rect.x = off_x;
glyph->rect.y = off_y;
glyph->rect.w = block_width;
glyph->rect.h = block_height;
glyph->advance = fullsize->advance / (float)size->denominator;
free(pixels);
free(acc);
return true;
}
static float fnl_font_size_char(struct font_size *_size, uint32_t code)
{
struct fnl_font_size *size = (struct fnl_font_size*)_size;
unsigned index = fnl_char_to_index(code);
if (index > size->bitmap_size->nr_glyphs)
return 0.0;
if (!size->bitmap_size->face->glyphs[index].data_pos)
return 0.0;
float r = (float)size->bitmap_size->face->glyphs[index].real_width / (float)size->denominator;
if (code == '\t')
r *= 2.88;
return r;
}
struct font *fnl_font_load(struct fnl *lib, unsigned index)
{
if (index >= lib->nr_fonts)
return NULL;
struct fnl_font *lib_font = &lib->fonts[index];
struct font_fnl *font = xcalloc(1, sizeof(struct font_fnl));
// initialize bitmap sizes
font->nr_bitmap_sizes = lib_font->nr_faces;
font->bitmap_sizes = xcalloc(font->nr_bitmap_sizes, sizeof(struct fnl_bitmap_size));
for (unsigned i = 0; i < font->nr_bitmap_sizes; i++) {
struct fnl_bitmap_size *bitsize = &font->bitmap_sizes[i];
bitsize->face = &lib_font->faces[i];
bitsize->nr_glyphs = bitsize->face->nr_glyphs;
bitsize->glyphs = xcalloc(bitsize->nr_glyphs, sizeof(struct fnl_bitmap_glyph*));
}
// initialize render sizes (downscaled)
font->nr_sizes = font->nr_bitmap_sizes * 12;
font->sizes = xcalloc(font->nr_sizes, sizeof(struct fnl_font_size));
for (unsigned i = 0; i < font->nr_bitmap_sizes; i++) {
struct fnl_bitmap_size *bitsize = &font->bitmap_sizes[i];
struct fnl_font_size *sizes = &font->sizes[i*12];
for (unsigned i = 0; i < 12; i++) {
sizes[i].bitmap_size = bitsize;
sizes[i].super.size = bitsize->face->height / (float)(i+1);
sizes[i].super.font = &font->super;
sizes[i].denominator = i + 1;
}
}
font->super.charmap = CHARMAP_SJIS;
font->super.get_size = fnl_font_get_size;
font->super.get_actual_size = fnl_font_get_actual_size;
font->super.get_actual_size_round_down = fnl_font_get_actual_size_round_down;
font->super.get_glyph = fnl_font_get_glyph;
font->super.size_char = fnl_font_size_char;
if (!game_rance7_mg)
gfx_text_advance_edges = true;
return &font->super;
}
+210
View File
@@ -0,0 +1,210 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_BITMAP_H
#include "system4.h"
#include "system4/hashtable.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "gfx/gfx.h"
#include "gfx/font.h"
#include "xsystem4.h"
#define MAX_FONT_SIZES 64
struct font_ft {
struct font super;
FT_Face font;
unsigned current_size;
unsigned nr_sizes;
struct font_size sizes[MAX_FONT_SIZES];
};
static FT_Library ft_lib;
static bool is_half_width(uint32_t code)
{
// ASCII characters
if (code < 128)
return true;
// Latin letters
if (0xbf <= code && code <= 0xff && code != 0xd7 && code != 0xf7)
return true;
// Halfwidth punctuation / katakana
if (0xff61 <= code && code <= 0xff9f)
return true;
return false;
}
void ft_font_init(void)
{
if (FT_Init_FreeType(&ft_lib)) {
ERROR("Failed to initialize FreeType");
}
}
static struct font_size *ft_font_get_size(struct font *_font, float size)
{
struct font_ft *font = (struct font_ft*)_font;
size = roundf(size);
for (int i = 0; i < font->nr_sizes; i++) {
if (fabsf(font->sizes[i].size - size) < 0.01) {
return &font->sizes[i];
}
}
if (font->nr_sizes + 1 >= MAX_FONT_SIZES)
ERROR("Exceeded maximum number of font sizes");
struct font_size *fs = &font->sizes[font->nr_sizes++];
fs->size = size;
fs->y_offset = -roundf(size * 0.15f);
fs->font = _font;
fs->glyph_table = ht_create(4096);
return fs;
}
static float ft_font_get_actual_size(struct font *_, float size)
{
return roundf(size);
}
// NOTE: we create glyph textures slightly larger than necessary so that outlines
// aren't cut off at the texture boundary.
// FIXME: the outline rendering code should be fixed so this isn't necessary.
#define GLYPH_BORDER_SIZE 4
// Convert a glyph rendered by FreeType to a block-sized texture.
// Block size is size x 1.5*size (full-width) or size/2 x 1.5*size (half-width)
static Rectangle init_glyph_texture(Texture *dst, FT_Bitmap *glyph, int bitmap_left, int bitmap_top, int size, bool half_width)
{
// calculate block size and offsets
int block_width = (half_width ? size/2 : size);
int block_height = size + size/2;
int width = block_width + GLYPH_BORDER_SIZE*2;
int height = block_height + GLYPH_BORDER_SIZE*2;
int off_x = max(0, bitmap_left) + GLYPH_BORDER_SIZE;
int off_y = max(0, size - bitmap_top) + GLYPH_BORDER_SIZE;
uint8_t *bitmap = xcalloc(1, width * height);
// Expand the glyph bitmap to block size
for (int row = 0; row < glyph->rows && row + off_y < height; row++) {
for (int col = 0; col < glyph->width && col + off_x < width; col++) {
uint8_t p = glyph->buffer[row*glyph->width + col];
bitmap[(row+off_y)*width + (col+off_x)] = p;
}
}
// create texture from block-size bitmap
gfx_init_texture_rmap(dst, width, height, bitmap);
free(bitmap);
return (Rectangle) {
.x = GLYPH_BORDER_SIZE,
.y = GLYPH_BORDER_SIZE,
.w = block_width,
.h = block_height
};
}
static void ft_font_set_size(struct font_ft *font, unsigned size)
{
if (font->current_size != size && FT_Set_Pixel_Sizes(font->font, 0, size)) {
WARNING("Failed setting font size to %u", size);
}
font->current_size = size;
}
static bool ft_font_get_glyph(struct font_size *size, struct glyph *glyph, uint32_t code, enum font_weight weight)
{
Texture *t = &glyph->t[weight];
// render bitmap
bool half_width = is_half_width(code);
struct font_ft *font = (struct font_ft*)size->font;
ft_font_set_size(font, size->size);
if (FT_Load_Char(font->font, code, FT_LOAD_RENDER)) {
WARNING("Failed to load glyph for codepoint 0x%x", code);
return false;
}
if (weight != FONT_WEIGHT_NORMAL) {
int bold_weight = weight == FONT_WEIGHT_HEAVY ? 128 : 64;
FT_GlyphSlot_Own_Bitmap(font->font->glyph);
FT_Bitmap_Embolden(ft_lib, &font->font->glyph->bitmap, bold_weight, 0);
}
// create texture from bitmap
FT_Bitmap *bitmap = &font->font->glyph->bitmap;
if (bitmap->pixel_mode == FT_PIXEL_MODE_GRAY) {
glyph->rect = init_glyph_texture(t, bitmap, font->font->glyph->bitmap_left,
font->font->glyph->bitmap_top, size->size, half_width);
} else if (bitmap->pixel_mode == FT_PIXEL_MODE_MONO) {
FT_Bitmap tmp;
FT_Bitmap_New(&tmp);
if (FT_Bitmap_Convert(ft_lib, &font->font->glyph->bitmap, &tmp, 1)) {
WARNING("Failed to convert monochrome glyph to grayscale");
FT_Bitmap_Done(ft_lib, &tmp);
return false;
}
// round non-zero values up to 255 because FreeType doesn't
for (int i = 0; i < tmp.rows * tmp.width; i++) {
if (tmp.buffer[i])
tmp.buffer[i] = 255;
}
glyph->rect = init_glyph_texture(t, &tmp, font->font->glyph->bitmap_left,
font->font->glyph->bitmap_top, size->size, half_width);
FT_Bitmap_Done(ft_lib, &tmp);
} else {
WARNING("Font returned glyph with unsupported pixel mode");
return false;
}
glyph->advance = half_width ? size->size / 2 : size->size;
return true;
}
static float ft_font_size_char(struct font_size *size, uint32_t code)
{
return is_half_width(code) ? size->size / 2 : size->size;
}
struct font *ft_font_load(const char *path)
{
struct font_ft *font = xcalloc(1, sizeof(struct font_ft));
if (FT_New_Face(ft_lib, path, 0, &font->font)) {
free(font);
return NULL;
}
if (!font->font->charmap) {
WARNING("Font '%s' doesn't contain unicode charmap", path);
free(font);
return NULL;
}
font->super.get_size = ft_font_get_size;
font->super.get_actual_size = ft_font_get_actual_size;
font->super.get_actual_size_round_down = ft_font_get_actual_size;
font->super.get_glyph = ft_font_get_glyph;
font->super.size_char = ft_font_size_char;
return &font->super;
}
+176
View File
@@ -0,0 +1,176 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "system4.h"
#include "system4/ain.h"
#include "system4/buffer.h"
#include "system4/instructions.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "gfx/gfx.h"
#include "xsystem4.h"
#include "hll/hll.h"
bool game_daibanchou_en = false;
bool game_rance02_mg = false;
bool game_rance6_mg = false;
bool game_rance7_mg = false;
bool id_indexed_afa = false;
static void write_instruction0(struct buffer *out, enum opcode op)
{
buffer_write_int16(out, op);
}
static void write_instruction1(struct buffer *out, enum opcode op, int32_t arg)
{
buffer_write_int16(out, op);
buffer_write_int32(out, arg);
}
// Rance 02 (MangaGamer version)
// -----------------------------
// Uses a custom proportional font implementation which makes assumptions
// about the font. We replace the _CalculateWidth function with a font-generic
// implementation.
//
// '^' character is mapped to 'é' (Rosé)
// '}' character is mapped to double-width dash
static void apply_rance02_hacks(struct ain *ain)
{
int fno = ain_get_function(ain, "_CalculateWidth");
if (fno <= 0) {
WARNING("No '_CalculateWidth' function when applying Rance 02 compatibility hack");
return;
}
struct ain_function *f = &ain->functions[fno];
// Reduce the text scale if it wasn't set by the user
if (!config.manual_text_x_scale) {
config.text_x_scale = 0.9375;
}
// rewrite function
struct buffer out;
buffer_init(&out, ain->code, ain->code_size);
buffer_seek(&out, f->address);
// _CalculateWidth(ref string str, int nFontSize, int nWeightSize) {
// if (str[0] > 255 || str[0] == '}')
// return nFontSize + nWeightSize;
// return nFontSize / 2 + nWeightSize;
// }
// if (str[0] > 255 || str[0] == '}')
write_instruction1(&out, SH_LOCALREF, 0);
write_instruction1(&out, PUSH, 0);
write_instruction0(&out, C_REF);
write_instruction0(&out, DUP);
write_instruction1(&out, PUSH, 255);
write_instruction0(&out, GT);
write_instruction0(&out, SWAP);
write_instruction1(&out, PUSH, '}');
write_instruction0(&out, EQUALE);
write_instruction0(&out, OR);
int ifz_addr = out.index;
write_instruction1(&out, IFZ, 0);
// return nFontSize + nWeightSize
write_instruction1(&out, SH_LOCALREF, 1);
write_instruction1(&out, SH_LOCALREF, 2);
write_instruction0(&out, ADD);
int jump_addr = out.index;
write_instruction1(&out, JUMP, 0);
// return nFontSize / 2 + nWeightSize;
buffer_write_int32_at(&out, ifz_addr + 2, out.index);
write_instruction1(&out, SH_LOCALREF, 1);
write_instruction1(&out, PUSH, 2);
write_instruction0(&out, DIV);
write_instruction1(&out, SH_LOCALREF, 2);
write_instruction0(&out, ADD);
// multiply by config.text_x_scale (if not 1.0)
buffer_write_int32_at(&out, jump_addr + 2, out.index);
if (fabsf(1.0 - config.text_x_scale) > 0.01) {
union { int32_t i; float f; } cast = { .f = config.text_x_scale };
write_instruction0(&out, ITOF);
write_instruction1(&out, F_PUSH, cast.i);
write_instruction0(&out, F_MUL);
write_instruction0(&out, FTOI);
}
write_instruction0(&out, RETURN);
write_instruction1(&out, ENDFUNC, fno);
game_rance02_mg = true;
}
// Rance VI (MangaGamer version)
// -----------------------------
// 'ノ' character is mapped to 'é' (Rosé)
static void apply_rance6_hacks(struct ain *ain)
{
if (ain_get_function(ain, "GetTextWidth") < 0)
return;
game_rance6_mg = true;
}
static void apply_rance7_hacks(struct ain *ain)
{
if (ain_get_library(ain, "SengokuRanceFont") < 0)
return;
game_rance7_mg = true;
}
// Daibanchou (English fan translation)
// ------------------------------------
// Gpx2Plus.CopyStretchReduceAMap behaves differently in order to work around
// text rendering issues caused by how the game calculates text width in
// StructRegionalSelect::DrawMenuItem.
static void apply_daibanchou_hacks(struct ain *ain)
{
if (ain->nr_strings > 2 && !strcmp(ain->strings[2]->text, "Seijou Academy")) {
game_daibanchou_en = true;
}
}
void apply_game_specific_hacks(struct ain *ain)
{
char *game_name = sjis2utf(config.game_name, 0);
if (!strcmp(game_name, "大番長")) {
apply_daibanchou_hacks(ain);
} else if (!strcmp(game_name, "Rance 02")) {
apply_rance02_hacks(ain);
} else if (!strcmp(game_name, "Rance6")) {
apply_rance6_hacks(ain);
} else if (!strcmp(game_name, "Sengoku Rance")) {
apply_rance7_hacks(ain);
} else if (!strcmp(game_name, "しゃーまんず・さんくちゅあり 巫女の聖域")) {
id_indexed_afa = true;
} else if (!strcmp(game_name, "大帝国")) {
id_indexed_afa = true;
}
free(game_name);
}
+104 -20
View File
@@ -23,6 +23,7 @@
#include "vm.h"
#include "vm/heap.h"
#include "vm/page.h"
#include "xsystem4.h"
#define INITIAL_HEAP_SIZE 4096
#define HEAP_ALLOC_STEP 4096
@@ -98,7 +99,10 @@ int32_t heap_alloc_slot(enum vm_pointer_type type)
heap[slot].type = type;
#ifdef DEBUG_HEAP
heap[slot].alloc_addr = instr_ptr;
heap[slot].ref_addr = 0;
memset(heap[slot].ref_addr, 0, sizeof(heap[slot].ref_addr));
heap[slot].ref_nr = 0;
memset(heap[slot].deref_addr, 0, sizeof(heap[slot].deref_addr));
heap[slot].deref_nr = 0;
heap[slot].free_addr = 0;
#endif
return slot;
@@ -109,26 +113,37 @@ static void heap_free_slot(int32_t slot)
heap_free_stack[--heap_free_ptr] = slot;
}
static void heap_double_free(int32_t slot)
{
#ifdef DEBUG_HEAP
WARNING("double free of slot %d (%s)\nOriginally allocated at %X\nOriginally freed at %X",
slot, vm_ptrtype_string(heap[slot].type),
heap[slot].alloc_addr, heap[slot].free_addr);
#else
WARNING("double free of slot %d (%s)", slot, vm_ptrtype_string(heap[slot].type));
#endif
}
void heap_ref(int32_t slot)
{
if (slot == -1)
return;
heap[slot].ref++;
#ifdef DEBUG_HEAP
heap[slot].ref_addr = instr_ptr;
heap[slot].ref_addr[heap[slot].ref_nr++ % 16] = instr_ptr;
#endif
}
void heap_unref(int slot)
{
if (heap[slot].ref <= 0) {
#ifdef DEBUG_HEAP
VM_ERROR("double free of slot %d (%s)\nOriginally allocated at %X\nOriginally freed at %X",
slot, vm_ptrtype_string(heap[slot].type), heap[slot].alloc_addr, heap[slot].free_addr);
#endif
VM_ERROR("double free of slot %d (%s)", slot, vm_ptrtype_string(heap[slot].type));
if (unlikely(heap[slot].ref <= 0)) {
heap_double_free(slot);
VM_ERROR("double free");
}
if (heap[slot].ref > 1) {
#ifdef DEBUG_HEAP
heap[slot].deref_addr[heap[slot].deref_nr++ % 16] = instr_ptr;
#endif
heap[slot].ref--;
return;
}
@@ -157,10 +172,13 @@ void exit_unref(int slot)
return;
}
if (heap[slot].ref <= 0) {
WARNING("double free of slot %d", slot);
heap_double_free(slot);
return;
}
if (heap[slot].ref > 1) {
#ifdef DEBUG_HEAP
heap[slot].deref_addr[heap[slot].deref_nr++ % 16] = 0xDEADC0DE;
#endif
heap[slot].ref--;
return;
}
@@ -172,6 +190,7 @@ void exit_unref(int slot)
switch (variable_type(page, i, NULL, NULL)) {
case AIN_STRING:
case AIN_STRUCT:
case AIN_DELEGATE:
case AIN_ARRAY_TYPE:
case AIN_REF_TYPE:
if (page->values[i].i == -1)
@@ -210,14 +229,14 @@ bool string_index_valid(int index)
struct page *heap_get_page(int index)
{
if (!page_index_valid(index))
if (unlikely(!page_index_valid(index)))
VM_ERROR("Invalid page index: %d", index);
return heap[index].page;
}
struct string *heap_get_string(int index)
{
if (!string_index_valid(index))
if (unlikely(!string_index_valid(index)))
VM_ERROR("Invalid string index: %d", index);
return heap[index].s;
}
@@ -225,7 +244,7 @@ struct string *heap_get_string(int index)
struct page *heap_get_delegate_page(int index)
{
struct page *page = heap_get_page(index);
if (page && page->type != DELEGATE_PAGE)
if (unlikely(page && page->type != DELEGATE_PAGE))
VM_ERROR("Not a delegate page: %d", index);
return page;
}
@@ -233,7 +252,7 @@ struct page *heap_get_delegate_page(int index)
void heap_set_page(int slot, struct page *page)
{
#ifdef DEBUG_HEAP
if (!page_index_valid(slot))
if (unlikely(!page_index_valid(slot)))
VM_ERROR("Invalid page index: %d", index);
#endif
heap[slot].page = page;
@@ -242,7 +261,7 @@ void heap_set_page(int slot, struct page *page)
void heap_string_assign(int slot, struct string *string)
{
#ifdef DEBUG_HEAP
if (!string_index_valid(slot))
if (unlikely(!string_index_valid(slot)))
VM_ERROR("Tried to assign string to non-string slot");
#endif
if (heap[slot].s) {
@@ -253,20 +272,20 @@ void heap_string_assign(int slot, struct string *string)
void heap_struct_assign(int lval, int rval)
{
if (lval == -1)
if (unlikely(lval == -1))
VM_ERROR("Assignment to null-pointer");
if (lval == rval)
return;
#ifdef DEBUG_HEAP
if (!page_index_valid(lval))
if (unlikely(!page_index_valid(lval)))
VM_ERROR("Invalid page index: %d", lval);
if (!page_index_valid(rval))
if (unlikely(!page_index_valid(rval)))
VM_ERROR("Invalid page index: %d", rval);
if (heap[lval].page && heap[lval].page->type != STRUCT_PAGE)
if (unlikely(heap[lval].page && heap[lval].page->type != STRUCT_PAGE))
VM_ERROR("SR_ASSIGN to non-struct page");
if (heap[rval].page && heap[rval].page->type != STRUCT_PAGE)
if (unlikely(heap[rval].page && heap[rval].page->type != STRUCT_PAGE))
VM_ERROR("SR_ASSIGN from non-struct page");
if (heap[lval].page && heap[rval].page && heap[lval].page->index != heap[rval].page->index)
if (unlikely(heap[lval].page && heap[rval].page && heap[lval].page->index != heap[rval].page->index))
VM_ERROR("SR_ASSIGN with different struct types");
#endif
if (heap[lval].page) {
@@ -288,3 +307,68 @@ int32_t heap_alloc_page(struct page *page)
heap[slot].page = page;
return slot;
}
static void describe_page(struct page *page)
{
if (!page) {
sys_message("NULL_PAGE\n");
return;
}
switch (page->type) {
case GLOBAL_PAGE:
sys_message("GLOBAL_PAGE\n");
break;
case LOCAL_PAGE:
sys_message("LOCAL_PAGE: %s\n", display_sjis0(ain->functions[page->index].name));
break;
case STRUCT_PAGE:
sys_message("STRUCT_PAGE: %s\n", display_sjis0(ain->structures[page->index].name));
break;
case ARRAY_PAGE:
sys_message("ARRAY_PAGE: %s\n", display_sjis0(ain_strtype(ain, page->a_type, page->array.struct_type)));
break;
case DELEGATE_PAGE:
// TODO: list function names
sys_message("DELEGATE_PAGE\n");
break;
}
}
void heap_describe_slot(int slot)
{
if (heap[slot].type == VM_STRING && heap[slot].s == &EMPTY_STRING)
return;
#ifdef DEBUG_HEAP
sys_message("[%d](%d)(%08X)[", slot, heap[slot].ref, heap[slot].alloc_addr);
for (int i = 0; i < heap[slot].ref_nr && i < 16; i++) {
if (i > 0)
sys_message(",");
sys_message("%08X", heap[slot].ref_addr[i]);
}
sys_message("][");
for (int i = 0; i < heap[slot].deref_nr && i < 16; i++) {
if (i > 0)
sys_message(",");
sys_message("%08X", heap[slot].deref_addr[i]);
}
sys_message("] = ");
#else
sys_message("[%d](%d) = ", slot, heap[slot].ref);
#endif
switch (heap[slot].type) {
case VM_PAGE:
describe_page(heap[slot].page);
break;
case VM_STRING:
if (heap[slot].s) {
sys_message("STRING: %s\n", display_sjis0(heap[slot].s->text));
} else {
sys_message("STRING: NULL\n");
}
break;
default:
sys_message("???\n");
break;
}
}
+2 -2
View File
@@ -50,9 +50,9 @@ static bool ACXLoader_Load(struct string *filename)
}
if (error == ACX_ERROR_FILE) {
WARNING("acx_load(\"%s\"): %s", path, strerror(errno));
WARNING("acx_load(\"%s\"): %s", display_utf0(path), strerror(errno));
} else if (error == ACX_ERROR_INVALID) {
WARNING("acx_load(\"%s\"): invalid .acx file");
WARNING("acx_load(\"%s\"): invalid .acx file", display_utf0(path));
}
free(path);
return !!acx;
+26 -11
View File
@@ -19,6 +19,7 @@
#include "system4/utfsjis.h"
#include "vm/page.h"
#include "xsystem4.h"
#include "AnteaterADVEngine.h"
#include "iarray.h"
@@ -219,6 +220,7 @@ bool ADVLogList_Save(struct page **iarray)
free_page(*iarray);
}
*iarray = iarray_to_page(&b);
iarray_free_writer(&b);
return true;
}
@@ -308,7 +310,14 @@ bool ADVSceneKeeper_AddADVScene(struct page **page)
return false;
}
scenes.data = xrealloc_array(scenes.data, scenes.n, scenes.n+1, sizeof(struct page*));
scenes.data[scenes.n++] = copy_page(*page);
// serialize
struct iarray_writer out;
iarray_init_writer(&out, "SCN");
iarray_write_struct(&out, *page);
scenes.data[scenes.n++] = iarray_to_page(&out);
iarray_free_writer(&out);
return true;
}
@@ -322,19 +331,23 @@ bool ADVSceneKeeper_GetADVScene(int index, struct page **page)
if (index < 0 || (unsigned)index >= scenes.n)
return false;
// deserialize
struct iarray_reader in;
if (!iarray_init_reader(&in, scenes.data[index], "SCN"))
return false;
if (*page) {
delete_page_vars(*page);
free_page(*page);
}
*page = copy_page(scenes.data[index]);
return true;
*page = iarray_read_struct(&in, scene_struct_no());
return !in.error;
}
void ADVSceneKeeper_Clear(void)
{
for (unsigned i = 0; i < scenes.n; i++) {
delete_page_vars(scenes.data[i]);
free_page(scenes.data[i]);
}
free(scenes.data);
@@ -352,11 +365,11 @@ bool ADVSceneKeeper_Save(struct page **iarray)
// this implementation just serializes whatever it's given. Note
// also that the structure of 画面保管_t objects differs between games.
struct iarray_writer w;
iarray_init_writer(&w, "ADS");
iarray_write(&w, 3); // version? Mankuchu puts 3 here
iarray_init_writer(&w, "SCS");
iarray_write(&w, 0); // version
iarray_write(&w, scenes.n);
for (unsigned i = 0; i < scenes.n; i++) {
iarray_write_struct(&w, scenes.data[i]);
iarray_write_array(&w, scenes.data[i]);
}
*iarray = iarray_to_page(&w);
iarray_free_writer(&w);
@@ -371,10 +384,12 @@ bool ADVSceneKeeper_Load(struct page **iarray)
ADVSceneKeeper_Clear();
struct iarray_reader r;
iarray_init_reader(&r, *iarray, "ADS");
iarray_init_reader(&r, *iarray, "SCS");
if (iarray_read(&r) != 3)
if (iarray_read(&r) != 0) {
WARNING("Unsupported version of ADVSceneKeeper 'SCS' data");
goto error;
}
int nr_scenes = iarray_read(&r);
if (nr_scenes < 0 || nr_scenes > 10000)
@@ -383,9 +398,9 @@ bool ADVSceneKeeper_Load(struct page **iarray)
scenes.n = 0;
scenes.data = xcalloc(nr_scenes, sizeof(struct page*));
int struct_type = scene_struct_no();
for (int i = 0; i < nr_scenes; i++) {
scenes.data[scenes.n++] = iarray_read_struct(&r, struct_type);
struct ain_type type = { .data = AIN_ARRAY_INT, .struc = 0, .rank = 0 };
scenes.data[scenes.n++] = iarray_read_array(&r, &type);
if (r.error)
goto error;
}
+7 -6
View File
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <string.h>
#include "system4/file.h"
#include "system4/string.h"
#include "hll.h"
@@ -29,9 +30,9 @@
static int BanMisc_SaveStruct(struct page *page, struct string *file_name)
{
char *path = unix_path(file_name->text);
FILE *fp = fopen(path, "w");
FILE *fp = file_open_utf8(path, "w");
if (!fp) {
WARNING("Failed to open file '%s': %s", path, strerror(errno));
WARNING("Failed to open file '%s': %s", display_utf0(path), strerror(errno));
free(path);
return 0;
}
@@ -59,9 +60,9 @@ static int BanMisc_LoadStruct(struct page **_page, struct string *file_name)
}
char *path = unix_path(file_name->text);
FILE *fp = fopen(path, "r");
FILE *fp = file_open_utf8(path, "r");
if (!fp) {
WARNING("Failed to open file '%s': %s", path, strerror(errno));
WARNING("Failed to open file '%s': %s", display_utf0(path), strerror(errno));
free(path);
return 0;
}
@@ -101,7 +102,7 @@ HLL_WARN_UNIMPLEMENTED( , void, BanMisc, Init, void *imainsystem);
static void BanMisc_FadePlay(int ch, int num, int time, int volume, int loop)
{
bgm_prepare(ch, num - 1);
bgm_prepare(ch, num);
bgm_play(ch);
// TODO: fading
}
@@ -125,7 +126,7 @@ HLL_WARN_UNIMPLEMENTED(0, int, BanMisc, IsFade, int ch);
static int BanMisc_SoundLoad(int ch, int num)
{
return wav_prepare(ch, num - 1);
return wav_prepare(ch, num);
}
static void BanMisc_SoundPlay(int ch, int loop)
+54
View File
@@ -0,0 +1,54 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "asset_manager.h"
#include "xsystem4.h"
#include "hll.h"
static bool CGManager_Init(void *imain_system, int cg_cache_size)
{
return true;
}
static bool CGManager_LoadArchive(struct string *archive_name)
{
char *name = sjis2utf(archive_name->text, 0);
bool r = asset_manager_load_archive(ASSET_CG, name);
free(name);
return r;
}
//static int CGManager_GetCountOfDataFromArchive(void);
//static void CGManager_GetTitleByIndexFromArchive(int index, struct string **cg_name);
//static int CGManager_SearchTitleFromArchive(struct string *cg_name);
//static int CGManager_PrefixSearchTitleFromArchive(struct string *cg_name);
//static int CGManager_SuffixSearchTitleFromArchive(struct string *cg_name);
//static int CGManager_GetCountOfSearchDataFromArchive(void);
//static void CGManager_GetSearchTitleByIndexFromArchive(int index, struct string **cg_name);
HLL_LIBRARY(CGManager,
HLL_EXPORT(Init, CGManager_Init),
HLL_EXPORT(LoadArchive, CGManager_LoadArchive),
HLL_TODO_EXPORT(GetCountOfDataFromArchive, CGManager_GetCountOfDataFromArchive),
HLL_TODO_EXPORT(GetTitleByIndexFromArchive, CGManager_GetTitleByIndexFromArchive),
HLL_TODO_EXPORT(SearchTitleFromArchive, CGManager_SearchTitleFromArchive),
HLL_TODO_EXPORT(PrefixSearchTitleFromArchive, CGManager_PrefixSearchTitleFromArchive),
HLL_TODO_EXPORT(SuffixSearchTitleFromArchive, CGManager_SuffixSearchTitleFromArchive),
HLL_TODO_EXPORT(GetCountOfSearchDataFromArchive, CGManager_GetCountOfSearchDataFromArchive),
HLL_TODO_EXPORT(GetSearchTitleByIndexFromArchive, CGManager_GetSearchTitleByIndexFromArchive));
+52 -43
View File
@@ -22,7 +22,9 @@
#include "system4/utfsjis.h"
#include "vm/heap.h"
#include "vm/page.h"
#include "gfx/font.h"
#include "sprite.h"
#include "xsystem4.h"
#include "CharSpriteManager.h"
#include "iarray.h"
@@ -36,7 +38,7 @@ struct charsprite {
// NOTE: even though we only render a single character, we need to store an
// arbitrary string because CharSprite_GetChar returns it.
struct string *ch;
struct text_metrics tm;
struct text_style ts;
// NOTE: this is needed because we have to hide all sprites after loading
// regardless of their original visibility. When Rebuild is called,
// this value is used to correctly set the visibility.
@@ -163,14 +165,22 @@ static void charsprite_render(struct charsprite *cs)
char ch[3];
extract_sjis_char(cs->ch->text, ch);
int w = cs->tm.size;
int h = cs->tm.size;
// XXX: this is handled here and not in gfx_render_text because of the
// width calculation below
if (ch[0] == '}' && game_rance02_mg) {
ch[0] = 0x81;
ch[1] = 0x5c;
ch[2] = 0;
}
int w = cs->ts.size;
int h = cs->ts.size + cs->ts.size/2;
if (isascii(ch[0]))
w /= 2;
sprite_init(&cs->sp, w, h, 0, 0, 0, 0);
sprite_get_texture(&cs->sp); // XXX: force initialization of texture
gfx_render_text(&cs->sp.texture, (Point) { .x=0, .y = 0 }, ch, &cs->tm, 0);
gfx_render_text(&cs->sp.texture, 0.0f, 0, ch, &cs->ts);
sprite_dirty(&cs->sp);
}
@@ -228,19 +238,19 @@ bool CharSpriteManager_Save(struct page **iarray)
struct charsprite *s = chars.sprites[i];
iarray_write(&w, 1); // ???
iarray_write_string(&w, s->ch);
iarray_write(&w, s->tm.face);
iarray_write(&w, s->tm.size);
iarray_write(&w, s->tm.color.r);
iarray_write(&w, s->tm.color.g);
iarray_write(&w, s->tm.color.b);
iarray_write(&w, s->tm.color.a);
//iarray_write_float(&w, s->tm.weight);
iarray_write(&w, s->ts.face);
iarray_write(&w, s->ts.size);
iarray_write(&w, s->ts.color.r);
iarray_write(&w, s->ts.color.g);
iarray_write(&w, s->ts.color.b);
iarray_write(&w, s->ts.color.a);
//iarray_write_float(&w, s->ts.weight);
iarray_write_float(&w, 1.0);
iarray_write_float(&w, s->tm.outline_left);
iarray_write(&w, s->tm.outline_color.r);
iarray_write(&w, s->tm.outline_color.g);
iarray_write(&w, s->tm.outline_color.b);
iarray_write(&w, s->tm.outline_color.a);
iarray_write_float(&w, s->ts.edge_left);
iarray_write(&w, s->ts.edge_color.r);
iarray_write(&w, s->ts.edge_color.g);
iarray_write(&w, s->ts.edge_color.b);
iarray_write(&w, s->ts.edge_color.a);
iarray_write(&w, sprite_get_pos_x(&s->sp));
iarray_write(&w, sprite_get_pos_y(&s->sp));
iarray_write(&w, sprite_get_z(&s->sp));
@@ -290,21 +300,23 @@ bool CharSpriteManager_Load(struct page **data)
struct charsprite *cs = xcalloc(1, sizeof(struct charsprite));
iarray_read(&r); // ???
cs->ch = iarray_read_string(&r);
cs->tm.face = iarray_read(&r);
cs->tm.size = iarray_read(&r);
cs->tm.color.r = iarray_read(&r);
cs->tm.color.g = iarray_read(&r);
cs->tm.color.b = iarray_read(&r);
cs->tm.color.a = iarray_read(&r);
cs->tm.weight = FW_NORMAL; iarray_read_float(&r); // FIXME
cs->tm.outline_left = iarray_read_float(&r);
cs->tm.outline_up = cs->tm.outline_left;
cs->tm.outline_right = cs->tm.outline_left;
cs->tm.outline_down = cs->tm.outline_left;
cs->tm.outline_color.r = iarray_read(&r);
cs->tm.outline_color.g = iarray_read(&r);
cs->tm.outline_color.b = iarray_read(&r);
cs->tm.outline_color.a = iarray_read(&r);
cs->ts.face = iarray_read(&r);
cs->ts.size = iarray_read(&r);
cs->ts.color.r = iarray_read(&r);
cs->ts.color.g = iarray_read(&r);
cs->ts.color.b = iarray_read(&r);
cs->ts.color.a = iarray_read(&r);
cs->ts.weight = FW_NORMAL; iarray_read_float(&r); // FIXME
text_style_set_edge_width(&cs->ts, iarray_read_float(&r));
cs->ts.edge_color.r = iarray_read(&r);
cs->ts.edge_color.g = iarray_read(&r);
cs->ts.edge_color.b = iarray_read(&r);
cs->ts.edge_color.a = iarray_read(&r);
cs->ts.bold_width = 0.0f;
cs->ts.scale_x = 1.0f;
cs->ts.space_scale_x = 1.0f;
cs->ts.font_spacing = 0.0f;
cs->ts.font_size = NULL;
// sprite data
int x = iarray_read(&r);
@@ -364,27 +376,24 @@ static void CASColor_to_SDL_Color(SDL_Color *color, int page_no)
color->a = page->values[3].i;
}
static void CASCharSpriteProperty_to_text_metrics(struct text_metrics *tm, struct page *page)
static void CASCharSpriteProperty_to_text_style(struct text_style *ts, struct page *page)
{
assert(page);
assert(page->nr_vars == 6);
tm->face = page->values[0].i;
tm->size = page->values[1].i;
CASColor_to_SDL_Color(&tm->color, page->values[2].i);
//tm->weight = page->values[3].f;
tm->weight = FW_NORMAL;
tm->outline_left = page->values[4].f;
tm->outline_up = tm->outline_left;
tm->outline_right = tm->outline_left;
tm->outline_down = tm->outline_left;
CASColor_to_SDL_Color(&tm->outline_color, page->values[5].i);
ts->face = page->values[0].i;
ts->size = page->values[1].i;
CASColor_to_SDL_Color(&ts->color, page->values[2].i);
//ts->weight = page->values[3].f;
ts->weight = FW_NORMAL;
text_style_set_edge_width(ts, page->values[4].f);
CASColor_to_SDL_Color(&ts->edge_color, page->values[5].i);
}
void CharSprite_SetChar(int handle, struct string **s, struct page **property)
{
struct charsprite *sp = charsprite_get(handle);
CASCharSpriteProperty_to_text_metrics(&sp->tm, *property);
CASCharSpriteProperty_to_text_style(&sp->ts, *property);
if (charsprite_allocated(sp)) {
sprite_free(&sp->sp);
+105 -9
View File
@@ -14,25 +14,60 @@
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <assert.h>
#include "system4/cg.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "asset_manager.h"
#include "gfx/gfx.h"
#include "gfx/font.h"
#include "vm/page.h"
#include "input.h"
#include "sact.h"
#include "CharSpriteManager.h"
#include "xsystem4.h"
#include "hll.h"
static void ChipmunkSpriteEngine_PreLink(void);
static void ChipmunkSpriteEngine_ModuleFini(void)
{
sact_ModuleFini();
}
static int ChipmunkSpriteEngine_Init(void *imain_system, int cg_cache_size)
static int ChipmunkSpriteEngine_Init(void *imain_system)
{
asset_cg_index_init();
return sact_Init(imain_system, cg_cache_size);
return sact_Init(imain_system, 16);
}
static int ChipmunkSpriteEngine_SP_SetCG(int sp_no, struct string *cg_name)
{
struct sact_sprite *sp = sact_get_sprite(sp_no);
if (!sp) return 0;
return sprite_set_cg_by_name(sp, cg_name->text);
}
static int ChipmunkSpriteEngine_CG_IsExist(struct string *cg_name)
{
return asset_exists_by_name(ASSET_CG, cg_name->text, NULL);
}
static int ChipmunkSpriteEngine_CG_GetMetrics(struct string *cg_name, struct page **page)
{
union vm_value *cgm = (*page)->values;
struct cg_metrics metrics;
if (!asset_cg_get_metrics_by_name(cg_name->text, &metrics))
return 0;
cgm[0].i = metrics.w;
cgm[1].i = metrics.h;
cgm[2].i = metrics.bpp;
cgm[3].i = metrics.has_pixel;
cgm[4].i = metrics.has_alpha;
cgm[5].i = metrics.pixel_pitch;
cgm[6].i = metrics.alpha_pitch;
return 1;
}
HLL_WARN_UNIMPLEMENTED(0, int, ChipmunkSpriteEngine, SP_SetBrightness, int sp_no, int brightness);
@@ -44,6 +79,12 @@ HLL_WARN_UNIMPLEMENTED( , void, ChipmunkSpriteEngine, VIEW_SetOffsetPos, int x,
static bool keep_previous_view = true;
HLL_WARN_UNIMPLEMENTED((keep_previous_view = on, true), bool, ChipmunkSpriteEngine, KeepPreviousView_SetMode, bool on);
HLL_WARN_UNIMPLEMENTED(keep_previous_view, bool, ChipmunkSpriteEngine, KeepPreviousView_GetMode);
HLL_QUIET_UNIMPLEMENTED(false, bool, ChipmunkSpriteEngine, KeepPreviousView);
static void ChipmunkSpriteEngine_Sleep(void)
{
SDL_Delay(16);
}
//static bool ChipmunkSpriteEngine_SP_SetCutCG(int sp_no, int cg_no, int cut_x, int cut_y, int cut_w, int cut_h);
//static bool ChipmunkSpriteEngine_SP_SetMultipleColor(int sp_no, int r, int g, int b);
@@ -64,15 +105,24 @@ static bool ChipmunkSpriteEngine_SP_GetFontWidth(struct string *text, int *width
return true;
}
*width = SJIS_2BYTE(text->text[0]) ? text_sprite_tm.size : text_sprite_tm.size / 2;
*width = gfx_size_text(&text_sprite_ts, text->text);
return true;
}
//static bool ChipmunkSpriteEngine_SP_SetAlphaClipperSpriteNumber(int sp_no, int ac_sp_no);
//static int ChipmunkSpriteEngine_SP_GetAlphaClipperSpriteNumber(int sp_no);
//static int CG_GetFormat(int cg_no);
//static int CG_GetFormat_by_index(int cg_no);
//static int CG_GetFormat(struct string *cg_name);
//static bool ChipmunkSpriteEngine_SP_Suspend(int sp_no);
//static bool ChipmunkSpriteEngine_SP_Resume(int sp_no);
//static bool ChipmunkSpriteEngine_SP_IsSuspend(int sp_no);
//static bool ChipmunkSpriteEngine_Debug_GetVideoMemoryInfo(int *max_size, int *use_size, int *use_max_size);
//static void ChipmunkSpriteEngine_CombineTexture(void);
//static void ChipmunkSpriteEngine_ReleaseCombinedTexture(void);
HLL_LIBRARY(ChipmunkSpriteEngine,
HLL_EXPORT(_PreLink, ChipmunkSpriteEngine_PreLink),
HLL_EXPORT(_ModuleFini, ChipmunkSpriteEngine_ModuleFini),
HLL_EXPORT(Init, ChipmunkSpriteEngine_Init),
HLL_TODO_EXPORT(Error, SACT2_Error),
@@ -82,7 +132,7 @@ HLL_LIBRARY(ChipmunkSpriteEngine,
HLL_EXPORT(SP_GetUnuseNum, sact_SP_GetUnuseNum),
HLL_EXPORT(SP_Count, sact_SP_Count),
HLL_EXPORT(SP_Enum, sact_SP_Enum),
HLL_EXPORT(SP_SetCG, sact_SP_SetCG),
HLL_EXPORT(SP_SetCG, ChipmunkSpriteEngine_SP_SetCG),
HLL_TODO_EXPORT(SP_SetCutCG, ChipmunkSpriteEngine_SP_SetCutCG),
HLL_EXPORT(SP_SetCGFromFile, sact_SP_SetCGFromFile),
HLL_EXPORT(SP_SaveCG, sact_SP_SaveCG),
@@ -153,8 +203,9 @@ HLL_LIBRARY(ChipmunkSpriteEngine,
HLL_EXPORT(Key_IsDown, sact_Key_IsDown),
HLL_EXPORT(KEY_GetState, key_is_down),
HLL_EXPORT(Timer_Get, vm_time),
HLL_EXPORT(CG_IsExist, sact_CG_IsExist),
HLL_EXPORT(CG_GetMetrics, sact_CG_GetMetrics),
HLL_EXPORT(CG_IsExist, ChipmunkSpriteEngine_CG_IsExist),
HLL_EXPORT(CG_GetMetrics, ChipmunkSpriteEngine_CG_GetMetrics),
HLL_TODO_EXPORT(CG_GetFormat, ChipmunkSpriteEngine_CG_GetFormat),
HLL_EXPORT(System_GetDate, get_date),
HLL_EXPORT(System_GetTime, get_time),
HLL_TODO_EXPORT(CG_RotateRGB, SACT2_CG_RotateRGB),
@@ -178,6 +229,8 @@ HLL_LIBRARY(ChipmunkSpriteEngine,
HLL_TODO_EXPORT(DX_SetUsePower2Texture, SACTDX_DX_SetUsePower2Texture),
HLL_EXPORT(KeepPreviousView_SetMode, ChipmunkSpriteEngine_KeepPreviousView_SetMode),
HLL_EXPORT(KeepPreviousView_GetMode, ChipmunkSpriteEngine_KeepPreviousView_GetMode),
HLL_EXPORT(KeepPreviousView, ChipmunkSpriteEngine_KeepPreviousView),
HLL_EXPORT(Sleep, ChipmunkSpriteEngine_Sleep),
HLL_EXPORT(CharSpriteManager_CreateHandle, CharSpriteManager_CreateHandle),
HLL_EXPORT(CharSpriteManager_ReleaseHandle, CharSpriteManager_ReleaseHandle),
HLL_EXPORT(CharSpriteManager_Clear, CharSpriteManager_Clear),
@@ -206,5 +259,48 @@ HLL_LIBRARY(ChipmunkSpriteEngine,
HLL_TODO_EXPORT(Debug_GetCurrentAllocatedMemorySize, StoatSpriteEngine_Debug_GetCurrentAllocatedMemorySize),
HLL_TODO_EXPORT(Debug_GetMaxAllocatedMemorySize, StoatSpriteEngine_Debug_GetMaxAllocatedMemorySize),
HLL_TODO_EXPORT(Debug_GetFillRate, StoatSpriteEngine_Debug_GetFillRate),
HLL_TODO_EXPORT(MUSIC_ReloadParam, StoatSpriteEngine_MUSIC_ReloadParam));
HLL_TODO_EXPORT(MUSIC_ReloadParam, StoatSpriteEngine_MUSIC_ReloadParam),
HLL_TODO_EXPORT(SP_Suspend, ChipmunkSpriteEngine_SP_Suspend),
HLL_TODO_EXPORT(SP_Resume, ChipmunkSpriteEngine_SP_Resume),
HLL_TODO_EXPORT(SP_IsSuspend, ChipmunkSpriteEngine_SP_IsSuspend),
HLL_TODO_EXPORT(Debug_GetVideoMemoryInfo, ChipmunkSpriteEngine_Debug_GetVideoMemoryInfo),
HLL_TODO_EXPORT(CombineTexture, ChipmunkSpriteEngine_CombineTexture),
HLL_TODO_EXPORT(ReleaseCombinedTexture, ChipmunkSpriteEngine_ReleaseCombinedTexture));
static struct ain_hll_function *get_fun(int libno, const char *name)
{
int fno = ain_get_library_function(ain, libno, name);
return fno >= 0 ? &ain->libraries[libno].functions[fno] : NULL;
}
// Daiteikoku and Shaman's Sanctuary have different interface than later versions
static void ChipmunkSpriteEngine_PreLink(void)
{
struct ain_hll_function *fun;
int libno = ain_get_library(ain, "ChipmunkSpriteEngine");
assert(libno >= 0);
fun = get_fun(libno, "Init");
if (fun && fun->nr_arguments == 2) {
static_library_replace(&lib_ChipmunkSpriteEngine, "Init", sact_Init);
}
fun = get_fun(libno, "SP_SetCG");
if (fun && fun->arguments[1].type.data == AIN_INT) {
static_library_replace(&lib_ChipmunkSpriteEngine, "SP_SetCG", sact_SP_SetCG);
}
// TODO: SP_SetCutCG
fun = get_fun(libno, "CG_IsExist");
if (fun && fun->arguments[0].type.data == AIN_INT) {
static_library_replace(&lib_ChipmunkSpriteEngine, "CG_IsExist", sact_CG_IsExist);
}
fun = get_fun(libno, "CG_GetMetrics");
if (fun && fun->arguments[0].type.data == AIN_INT) {
static_library_replace(&lib_ChipmunkSpriteEngine, "CG_GetMetrics", sact_CG_GetMetrics);
}
// TODO: CG_GetFormat
}
+145
View File
@@ -0,0 +1,145 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdint.h>
#include "system4.h"
#include "system4/hashtable.h"
#include "system4/string.h"
#include "hll.h"
static struct string *save_path = NULL;
union csd_datum {
void *p;
intptr_t i;
float f;
struct string *s;
};
static struct hash_table *csd_table(void)
{
static struct hash_table *table = NULL;
if (!table) {
table = ht_create(64);
}
return table;
}
static void csd_put_datum(struct string *name, union csd_datum datum)
{
struct ht_slot *slot = ht_put(csd_table(), name->text, NULL);
slot->value = datum.p;
}
static bool csd_get_datum(struct string *name, union csd_datum *out)
{
return _ht_get(csd_table(), name->text, &out->p);
}
static void CommonSystemData_SetFullPathSaveFileName(struct string *filename)
{
if (save_path)
free_string(save_path);
save_path = string_dup(filename);
NOTICE("SetFullPathSaveFileName(%s)", filename->text);
}
HLL_WARN_UNIMPLEMENTED(false, bool, CommonSystemData, LoadAtStartup);
//static bool CommonSystemData_LoadAtStartup(void);
static bool CommonSystemData_SetDataInt(struct string *name, int value)
{
csd_put_datum(name, (union csd_datum) { .i = value });
return true;
}
static bool CommonSystemData_SetDataFloat(struct string *name, float value)
{
csd_put_datum(name, (union csd_datum) { .f = value });
return true;
}
static bool CommonSystemData_SetDataString(struct string *name, struct string *value)
{
union csd_datum datum = { .s = string_dup(value) };
struct ht_slot *slot = ht_put(csd_table(), name->text, NULL);
if (slot->value)
free_string(slot->value);
slot->value = datum.p;
return true;
}
static bool CommonSystemData_SetDataBool(struct string *name, bool value)
{
csd_put_datum(name, (union csd_datum) { .i = value });
return true;
}
static bool CommonSystemData_GetDataInt(struct string *name, int *value)
{
union csd_datum datum;
if (csd_get_datum(name, &datum)) {
*value = datum.i;
return true;
}
return false;
}
static bool CommonSystemData_GetDataFloat(struct string *name, float *value)
{
union csd_datum datum;
if (csd_get_datum(name, &datum)) {
*value = datum.f;
return true;
}
return false;
}
static bool CommonSystemData_GetDataString(struct string *name, struct string **value)
{
union csd_datum datum;
if (csd_get_datum(name, &datum)) {
if (*value)
free_string(*value);
*value = string_dup(datum.s);
return true;
}
return false;
}
static bool CommonSystemData_GetDataBool(struct string *name, bool *value)
{
union csd_datum datum;
if (csd_get_datum(name, &datum)) {
*value = datum.i;
return true;
}
return false;
}
HLL_LIBRARY(CommonSystemData,
HLL_EXPORT(SetFullPathSaveFileName, CommonSystemData_SetFullPathSaveFileName),
HLL_EXPORT(LoadAtStartup, CommonSystemData_LoadAtStartup),
HLL_EXPORT(SetDataInt, CommonSystemData_SetDataInt),
HLL_EXPORT(SetDataFloat, CommonSystemData_SetDataFloat),
HLL_EXPORT(SetDataString, CommonSystemData_SetDataString),
HLL_EXPORT(SetDataBool, CommonSystemData_SetDataBool),
HLL_EXPORT(GetDataInt, CommonSystemData_GetDataInt),
HLL_EXPORT(GetDataFloat, CommonSystemData_GetDataFloat),
HLL_EXPORT(GetDataString, CommonSystemData_GetDataString),
HLL_EXPORT(GetDataBool, CommonSystemData_GetDataBool));
+54
View File
@@ -0,0 +1,54 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include "hll.h"
HLL_WARN_UNIMPLEMENTED( , void, Confirm3, Init, void *iMainsystem);
HLL_WARN_UNIMPLEMENTED(0, int, Confirm3, GetHDDVolumeNumber, void);
HLL_WARN_UNIMPLEMENTED(5, int, Confirm3, GetDrive, struct string *filename);
HLL_WARN_UNIMPLEMENTED(0, int, Confirm3, GetRandom, int seed);
HLL_WARN_UNIMPLEMENTED(true, bool, Confirm3, File_Open, struct string *filename);
HLL_WARN_UNIMPLEMENTED(true, bool, Confirm3, File_Create, struct string *filename);
HLL_WARN_UNIMPLEMENTED(true, bool, Confirm3, File_SetPos, int pos);
static bool Confirm3_File_ReadByte(int *data)
{
*data = 0;
return true;
}
static bool Confirm3_File_ReadInt(int *data)
{
*data = 0;
return true;
}
HLL_WARN_UNIMPLEMENTED(true, bool, Confirm3, File_WriteInt, int data);
HLL_WARN_UNIMPLEMENTED(true, bool, Confirm3, File_Close, void);
HLL_LIBRARY(Confirm3,
HLL_EXPORT(Init, Confirm3_Init),
HLL_EXPORT(GetHDDVolumeNumber, Confirm3_GetHDDVolumeNumber),
HLL_EXPORT(GetDrive, Confirm3_GetDrive),
HLL_EXPORT(GetRandom, Confirm3_GetRandom),
HLL_EXPORT(File_Open, Confirm3_File_Open),
HLL_EXPORT(File_Create, Confirm3_File_Create),
HLL_EXPORT(File_SetPos, Confirm3_File_SetPos),
HLL_EXPORT(File_ReadByte, Confirm3_File_ReadByte),
HLL_EXPORT(File_ReadInt, Confirm3_File_ReadInt),
HLL_EXPORT(File_WriteInt, Confirm3_File_WriteInt),
HLL_EXPORT(File_Close, Confirm3_File_Close)
);
+3 -3
View File
@@ -17,7 +17,9 @@
#include "system4.h"
#include "system4/string.h"
#include "system4/utfsjis.h"
#include "hll.h"
#include "xsystem4.h"
bool is_opened = false;
@@ -43,9 +45,7 @@ HLL_WARN_UNIMPLEMENTED( , void, CrayfishLogViewer, SetWindowTitleName,
static bool CrayfishLogViewer_AddText(struct string *text)
{
char *u = sjis2utf(text->text, 0);
sys_message("%s", u);
free(u);
sys_message("%s", display_sjis0(text->text));
return true;
}
+42
View File
@@ -0,0 +1,42 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include "input.h"
#include "hll.h"
#define TT3_CURSOR_TRANSPARENT 11
HLL_WARN_UNIMPLEMENTED(1, int, Cursor, Load, int nNum, int nLinkNum);
static void Cursor_Set(int num)
{
switch (num) {
case 0:
mouse_show_cursor(true);
break;
case TT3_CURSOR_TRANSPARENT:
mouse_show_cursor(false);
break;
default:
WARNING("Cursor.Set: unexpected argument %d", num);
break;
}
}
HLL_LIBRARY(Cursor,
HLL_EXPORT(Load, Cursor_Load),
HLL_EXPORT(Set, Cursor_Set)
);
+120
View File
@@ -0,0 +1,120 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <zlib.h>
#include "system4/archive.h"
#include "system4/buffer.h"
#include "system4/string.h"
#include "hll.h"
#include "asset_manager.h"
#include "little_endian.h"
#include "vm/heap.h"
#include "vm/page.h"
#include "xsystem4.h"
static struct buffer reader;
static int Data_Exist(int num)
{
return asset_exists(ASSET_DATA, num);
}
static int Data_Open(int num)
{
struct archive_data *dfile = asset_get(ASSET_DATA, num);
if (!dfile)
return 0;
unsigned long uncompressed_size = LittleEndian_getDW(dfile->data, 0);
uint8_t *buf = xmalloc(uncompressed_size);
int rv = uncompress(buf, &uncompressed_size, (uint8_t *)dfile->data + 4, dfile->size - 4);
if (rv != Z_OK) {
WARNING("%s: uncompress failed (%d)", dfile->name, rv);
archive_free_data(dfile);
free(buf);
return 0;
}
archive_free_data(dfile);
if (reader.buf)
free(reader.buf);
buffer_init(&reader, buf, uncompressed_size);
return 1;
}
static int Data_Close(void)
{
if (!reader.buf)
return 0;
free(reader.buf);
reader.buf = NULL;
return 1;
}
static void read_struct(struct page *page)
{
if (page->type != STRUCT_PAGE) {
VM_ERROR("Data.Read of non-struct");
}
for (int i = 0; i < page->nr_vars; i++) {
int struct_type;
enum ain_data_type type = variable_type(page, i, &struct_type, NULL);
union vm_value val;
switch (type) {
case AIN_INT:
val = vm_int(buffer_read_int32(&reader));
break;
case AIN_FLOAT:
val = vm_float(buffer_read_float(&reader));
break;
case AIN_STRING:
{
struct string *s = cstr_to_string(buffer_strdata(&reader));
buffer_skip(&reader, s->size + 1);
val = vm_int(heap_alloc_string(s));
}
break;
case AIN_STRUCT:
{
int slot = alloc_struct(struct_type);
read_struct(heap[slot].page);
val = vm_int(slot);
}
break;
default:
VM_ERROR("Data.Read: unsupported data type");
}
variable_set(page, i, type, val);
}
}
static int Data_Read(struct page **page)
{
if (!reader.buf || buffer_remaining(&reader) == 0) {
return 0;
}
read_struct(*page);
return 1;
}
HLL_LIBRARY(Data,
HLL_EXPORT(Exist, Data_Exist),
HLL_EXPORT(Open, Data_Open),
HLL_EXPORT(Close, Data_Close),
HLL_EXPORT(Read, Data_Read)
);
+1 -1
View File
@@ -251,7 +251,7 @@ possibly_unused static void gdat_dump_as_json(struct gdat *dat, FILE *fp)
static int DataFile_Open(int link)
{
struct archive_data *dfile = asset_get(ASSET_DATA, link - 1);
struct archive_data *dfile = asset_get(ASSET_DATA, link);
if (!dfile) {
WARNING("Failed to load data file %d", link);
return 0;
-6
View File
@@ -46,12 +46,6 @@ struct dungeon_context *dungeon_get_context(int surface)
return current_context;
}
void dungeon_update(void)
{
if (current_context && current_context->loaded && current_context->draw_enabled)
dungeon_render(current_context);
}
static struct dgn_cell *dungeon_get_cell(int surface, int x, int y, int z)
{
struct dungeon_context *ctx = dungeon_get_context(surface);
+176 -97
View File
@@ -16,7 +16,8 @@
#include "hll.h"
#include "sact.h"
#include "gfx/types.h"
#include "gfx/gfx.h"
#include "gfx/font.h"
#include "system4/string.h"
// Get texture for source sprite
@@ -86,21 +87,71 @@ static void DrawGraph_Blend(int dst, int dx, int dy, int src, int sx, int sy, in
gfx_blend(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, alpha);
}
static void DrawGraph_BlendSrcBright(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int alpha, int rate)
{
gfx_blend_src_bright(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, alpha, rate);
}
static void DrawGraph_BlendAddSatur(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_blend_add_satur(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_BlendAMap(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_blend_amap(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_BlendAMapSrcOnly(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_blend_amap_src_only(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_BlendAMapColor(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int r, int g, int b)
{
gfx_blend_amap_color(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, r, g, b);
}
static void DrawGraph_BlendAMapColorAlpha(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int r, int g, int b, int a)
{
gfx_blend_amap_color_alpha(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, r, g, b, a);
}
static void DrawGraph_BlendAMapAlpha(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int alpha)
{
gfx_blend_amap_alpha(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, alpha);
}
static void DrawGraph_BlendAMapBright(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int rate)
{
gfx_blend_amap_bright(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, rate);
}
static void DrawGraph_BlendAMapAlphaSrcBright(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int alpha, int rate)
{
gfx_blend_amap_alpha_src_bright(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, alpha, rate);
}
static void DrawGraph_BlendUseAMapColor(int dst, int dx, int dy, int alpha, int ax, int ay, int w, int h, int r, int g, int b, int rate)
{
gfx_blend_use_amap_color(DTEX(dst), dx, dy, STEX(alpha), ax, ay, w, h, r, g, b, rate);
}
static void DrawGraph_BlendScreen(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_blend_screen(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_BlendMultiply(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_blend_multiply(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_BlendScreenAlpha(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int alpha)
{
gfx_blend_screen_alpha(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, alpha);
}
static void DrawGraph_Fill(int dst, int x, int y, int w, int h, int r, int g, int b)
{
gfx_fill(DTEX(dst), x, y, w, h, r, g, b);
@@ -116,11 +167,51 @@ static void DrawGraph_FillAMap(int dst, int x, int y, int w, int h, int alpha)
gfx_fill_amap(DTEX(dst), x, y, w, h, alpha);
}
static void DrawGraph_FillAMapOverBorder(int dst, int x, int y, int w, int h, int alpha, int border)
{
gfx_fill_amap_over_border(DTEX(dst), x, y, w, h, alpha, border);
}
static void DrawGraph_FillAMapUnderBorder(int dst, int x, int y, int w, int h, int alpha, int border)
{
gfx_fill_amap_under_border(DTEX(dst), x, y, w, h, alpha, border);
}
static void DrawGraph_FillAMapGradationUD(int dst, int x, int y, int w, int h, int up_a, int down_a)
{
gfx_fill_amap_gradation_ud(DTEX(dst), x, y, w, h, up_a, down_a);
}
static void DrawGraph_FillScreen(int dst, int x, int y, int w, int h, int r, int g, int b)
{
gfx_fill_screen(DTEX(dst), x, y, w, h, r, g, b);
}
static void DrawGraph_FillMultiply(int dst, int x, int y, int w, int h, int r, int g, int b)
{
gfx_fill_multiply(DTEX(dst), x, y, w, h, r, g, b);
}
static void DrawGraph_SaturDP_DPxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_satur_dp_dpxsa(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_ScreenDA_DAxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_screen_da_daxsa(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_AddDA_DAxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_add_da_daxsa(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_SpriteCopyAMap(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int key)
{
gfx_sprite_copy_amap(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, key);
}
static void DrawGraph_BlendDA_DAxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_blend_da_daxsa(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
@@ -131,16 +222,37 @@ static void DrawGraph_SubDA_DAxSA(int dst, int dx, int dy, int src, int sx, int
gfx_sub_da_daxsa(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_BrightDestOnly(int dst, int x, int y, int w, int h, int rate)
{
gfx_bright_dest_only(DTEX(dst), x, y, w, h, rate);
}
//void DrawGraph_CopyTextureWrap(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int u, int v);
//void DrawGraph_CopyTextureWrapAlpha(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int u, int v, int alpha);
static void DrawGraph_CopyStretch(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh)
{
gfx_copy_stretch(DTEX(dst), dx, dy, dw, dh, STEX(src), sx, sy, sw, sh);
}
static void DrawGraph_CopyStretchBlend(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int alpha)
{
gfx_copy_stretch_blend(DTEX(dst), dx, dy, dw, dh, STEX(src), sx, sy, sw, sh, alpha);
}
static void DrawGraph_CopyStretchBlendAMap(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh)
{
gfx_copy_stretch_blend_amap(DTEX(dst), dx, dy, dw, dh, STEX(src), sx, sy, sw, sh);
}
static void DrawGraph_CopyStretchAMap(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh)
{
gfx_copy_stretch_amap(DTEX(dst), dx, dy, dw, dh, STEX(src), sx, sy, sw, sh);
}
//void DrawGraph_CopyStretchInterp(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh);
//void DrawGraph_CopyStretchAMapInterp(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh);
static void DrawGraph_DrawTextToPMap(int dst, int x, int y, struct string *s)
{
gfx_draw_text_to_pmap(DTEX(dst), x, y, s->text);
@@ -151,6 +263,13 @@ static void DrawGraph_DrawTextToAMap(int dst, int x, int y, struct string *s)
gfx_draw_text_to_amap(DTEX(dst), x, y, s->text);
}
static void DrawGraph_SetFontName(struct string *text)
{
gfx_set_font_name(text->text);
}
HLL_WARN_UNIMPLEMENTED(string_ref(&EMPTY_STRING), struct string*, DrawGraph, GetFontName, void);
static void DrawGraph_SetFontColor(int r, int g, int b)
{
gfx_set_font_color(COLOR(r, g, b, 255));
@@ -179,82 +298,6 @@ static void DrawGraph_CopyRotZoomUseAMap(int dst, int src, int sx, int sy, int w
gfx_copy_rot_zoom_use_amap(DTEX(dst), STEX(src), sx, sy, w, h, rotate, mag);
}
static void DrawGraph_CopyReverseLR(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_copy_reverse_LR(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static void DrawGraph_CopyReverseAMapLR(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_copy_reverse_amap_LR(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
static bool DrawGraph_GetAlphaColor(int surface, int x, int y, int *a)
{
struct sact_sprite *sp = sact_get_sprite(surface);
// NOTE: System40.exe errors here
if (!sp)
VM_ERROR("Invalid sprite index: %d", surface);
if (x < 0 || x >= sp->rect.w || y < 0 || y >= sp->rect.h)
return false;
*a = sact_SP_GetAMapValue(surface, x, y);
return true;
}
static void DrawGraph_SetFontName(struct string *text)
{
gfx_set_font_name(text->text);
}
//void DrawGraph_BlendSrcBright(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int alpha, int rate);
//void DrawGraph_BlendAddSatur(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
//void DrawGraph_BlendAMapSrcOnly(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
//void DrawGraph_BlendAMapColorAlpha(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int r, int g, int b, int a);
//void DrawGraph_BlendAMapBright(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int rate);
//void DrawGraph_BlendAMapAlphaSrcBright(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int alpha, int rate);
//void DrawGraph_BlendUseAMapColor(int dst, int dx, int dy, int alpha, int ax, int ay, int w, int h, int r, int g, int b, int rate);
//void DrawGraph_BlendScreen(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
//void DrawGraph_BlendMultiply(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
//void DrawGraph_BlendScreenAlpha(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int alpha);
static void DrawGraph_FillAMapOverBorder(int dst, int x, int y, int w, int h, int alpha, int border)
{
gfx_fill_amap_over_border(DTEX(dst), x, y, w, h, alpha, border);
}
static void DrawGraph_FillAMapUnderBorder(int dst, int x, int y, int w, int h, int alpha, int border)
{
gfx_fill_amap_under_border(DTEX(dst), x, y, w, h, alpha, border);
}
//void DrawGraph_FillAMapGradationUD(int dst, int x, int y, int w, int h, int up_a, int down_a);
//void DrawGraph_FillScreen(int dst, int x, int y, int w, int h, int r, int g, int b);
//void DrawGraph_FillMultiply(int dst, int x, int y, int w, int h, int r, int g, int b);
//void DrawGraph_SaturDP_DPxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
//void DrawGraph_ScreenDA_DAxSA(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
static void DrawGraph_SpriteCopyAMap(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int key)
{
gfx_sprite_copy_amap(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h, key);
}
//void DrawGraph_BrightDestOnly(int dst, int x, int y, int w, int h, int rate);
//void DrawGraph_CopyTextureWrap(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int u, int v);
//void DrawGraph_CopyTextureWrapAlpha(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int u, int v, int alpha);
static void DrawGraph_CopyStretchBlend(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh, int alpha)
{
gfx_copy_stretch_blend(DTEX(dst), dx, dy, dw, dh, STEX(src), sx, sy, sw, sh, alpha);
}
static void DrawGraph_CopyStretchBlendAMap(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh)
{
gfx_copy_stretch_blend_amap(DTEX(dst), dx, dy, dw, dh, STEX(src), sx, sy, sw, sh);
}
//void DrawGraph_CopyStretchInterp(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh);
//void DrawGraph_CopyStretchAMapInterp(int dst, int dx, int dy, int dw, int dh, int src, int sx, int sy, int sw, int sh);
HLL_WARN_UNIMPLEMENTED(string_ref(&EMPTY_STRING), struct string*, DrawGraph, GetFontName, void);
//void DrawGraph_CopyRotZoom2Bilinear(int dst, float cx, float cy, int src, float scx, float scy, float rot, float mag);
static void DrawGraph_CopyRotateY(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag)
@@ -271,13 +314,34 @@ static void DrawGraph_CopyRotateYUseAMap(int write, int dst, int src, int sx, in
//void DrawGraph_CopyRotateYFixR(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
//void DrawGraph_CopyRotateYFixLUseAMap(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
//void DrawGraph_CopyRotateYFixRUseAMap(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
//void DrawGraph_CopyRotateX(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
//void DrawGraph_CopyRotateXUseAMap(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
static void DrawGraph_CopyRotateX(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag)
{
gfx_copy_rotate_x(DTEX(write), STEX(dst), STEX(src), sx, sy, w, h, rot, mag);
}
static void DrawGraph_CopyRotateXUseAMap(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag)
{
gfx_copy_rotate_x_use_amap(DTEX(write), STEX(dst), STEX(src), sx, sy, w, h, rot, mag);
}
//void DrawGraph_CopyRotateXFixU(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
//void DrawGraph_CopyRotateXFixD(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
//void DrawGraph_CopyRotateXFixUUseAMap(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
//void DrawGraph_CopyRotateXFixDUseAMap(int write, int dst, int src, int sx, int sy, int w, int h, float rot, float mag);
static void DrawGraph_CopyReverseLR(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_copy_reverse_LR(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
//void DrawGraph_CopyReverseUD(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
static void DrawGraph_CopyReverseAMapLR(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_copy_reverse_amap_LR(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
}
//void DrawGraph_CopyReverseAMapUD(int dst, int dx, int dy, int src, int sx, int sy, int w, int h);
static void DrawGraph_CopyWidthBlur(int dst, int dx, int dy, int src, int sx, int sy, int w, int h, int blur)
@@ -301,9 +365,24 @@ static void DrawGraph_CopyAMapHeightBlur(int dst, int dx, int dy, int src, int s
}
HLL_WARN_UNIMPLEMENTED( , void, DrawGraph, DrawLine, int dst, int x0, int y0, int x1, int y1, int r, int g, int b);
//void DrawGraph_DrawLineToAMap(int dst, int x0, int y0, int x1, int y1, int alpha);
static bool DrawGraph_GetAlphaColor(int surface, int x, int y, int *a)
{
struct sact_sprite *sp = sact_get_sprite(surface);
// NOTE: System40.exe errors here
if (!sp)
VM_ERROR("Invalid sprite index: %d", surface);
if (x < 0 || x >= sp->rect.w || y < 0 || y >= sp->rect.h)
return false;
*a = sact_SP_GetAMapValue(surface, x, y);
return true;
}
//void DrawGraph_DrawPolygon(int dst, int tex, float x0, float y0, float z0, float u0, float v0, float x1, float y1, float z1, float u1, float v1, float x2, float y2, float z2, float u2, float v2);
//void DrawGraph_DrawColorPolygon(int dst, int tex, float x0, float y0, float z0, int r0, int g0, int b0, int a0, float x1, float y1, float z1, int r1, int g1, int b1, int a1, float x2, float y2, float z2, int r2, int g2, int b2, int a2);
static void DrawGraph_CopyWithAlphaMap(int dst, int dx, int dy, int src, int sx, int sy, int w, int h)
{
gfx_copy_with_alpha_map(DTEX(dst), dx, dy, STEX(src), sx, sy, w, h);
@@ -332,34 +411,34 @@ HLL_LIBRARY(DrawGraph,
HLL_EXPORT(CopyAMapMax, DrawGraph_CopyAMapMax),
HLL_EXPORT(CopyAMapMin, DrawGraph_CopyAMapMin),
HLL_EXPORT(Blend, DrawGraph_Blend),
//HLL_EXPORT(BlendSrcBright, DrawGraph_BlendSrcBright),
//HLL_EXPORT(BlendAddSatur, DrawGraph_BlendAddSatur),
HLL_EXPORT(BlendSrcBright, DrawGraph_BlendSrcBright),
HLL_EXPORT(BlendAddSatur, DrawGraph_BlendAddSatur),
HLL_EXPORT(BlendAMap, DrawGraph_BlendAMap),
//HLL_EXPORT(BlendAMapSrcOnly, DrawGraph_BlendAMapSrcOnly),
HLL_EXPORT(BlendAMapSrcOnly, DrawGraph_BlendAMapSrcOnly),
HLL_EXPORT(BlendAMapColor, DrawGraph_BlendAMapColor),
//HLL_EXPORT(BlendAMapColorAlpha, DrawGraph_BlendAMapColorAlpha),
HLL_EXPORT(BlendAMapColorAlpha, DrawGraph_BlendAMapColorAlpha),
HLL_EXPORT(BlendAMapAlpha, DrawGraph_BlendAMapAlpha),
//HLL_EXPORT(BlendAMapBright, DrawGraph_BlendAMapBright),
//HLL_EXPORT(BlendAMapAlphaSrcBright, DrawGraph_BlendAMapAlphaSrcBright),
//HLL_EXPORT(BlendUseAMapColor, DrawGraph_BlendUseAMapColor),
//HLL_EXPORT(BlendScreen, DrawGraph_BlendScreen),
//HLL_EXPORT(BlendMultiply, DrawGraph_BlendMultiply),
//HLL_EXPORT(BlendScreenAlpha, DrawGraph_BlendScreenAlpha),
HLL_EXPORT(BlendAMapBright, DrawGraph_BlendAMapBright),
HLL_EXPORT(BlendAMapAlphaSrcBright, DrawGraph_BlendAMapAlphaSrcBright),
HLL_EXPORT(BlendUseAMapColor, DrawGraph_BlendUseAMapColor),
HLL_EXPORT(BlendScreen, DrawGraph_BlendScreen),
HLL_EXPORT(BlendMultiply, DrawGraph_BlendMultiply),
HLL_EXPORT(BlendScreenAlpha, DrawGraph_BlendScreenAlpha),
HLL_EXPORT(Fill, DrawGraph_Fill),
HLL_EXPORT(FillAlphaColor, DrawGraph_FillAlphaColor),
HLL_EXPORT(FillAMap, DrawGraph_FillAMap),
HLL_EXPORT(FillAMapOverBorder, DrawGraph_FillAMapOverBorder),
HLL_EXPORT(FillAMapUnderBorder, DrawGraph_FillAMapUnderBorder),
//HLL_EXPORT(FillAMapGradationUD, DrawGraph_FillAMapGradationUD),
//HLL_EXPORT(FillScreen, DrawGraph_FillScreen),
//HLL_EXPORT(FillMultiply, DrawGraph_FillMultiply),
//HLL_EXPORT(SaturDP_DPxSA, DrawGraph_SaturDP_DPxSA),
//HLL_EXPORT(ScreenDA_DAxSA, DrawGraph_ScreenDA_DAxSA),
HLL_EXPORT(FillAMapGradationUD, DrawGraph_FillAMapGradationUD),
HLL_EXPORT(FillScreen, DrawGraph_FillScreen),
HLL_EXPORT(FillMultiply, DrawGraph_FillMultiply),
HLL_EXPORT(SaturDP_DPxSA, DrawGraph_SaturDP_DPxSA),
HLL_EXPORT(ScreenDA_DAxSA, DrawGraph_ScreenDA_DAxSA),
HLL_EXPORT(AddDA_DAxSA, DrawGraph_AddDA_DAxSA),
HLL_EXPORT(SpriteCopyAMap, DrawGraph_SpriteCopyAMap),
HLL_EXPORT(BlendDA_DAxSA, DrawGraph_BlendDA_DAxSA),
HLL_EXPORT(SubDA_DAxSA, DrawGraph_SubDA_DAxSA),
//HLL_EXPORT(BrightDestOnly, DrawGraph_BrightDestOnly),
HLL_EXPORT(BrightDestOnly, DrawGraph_BrightDestOnly),
//HLL_EXPORT(CopyTextureWrap, DrawGraph_CopyTextureWrap),
//HLL_EXPORT(CopyTextureWrapAlpha, DrawGraph_CopyTextureWrapAlpha),
HLL_EXPORT(CopyStretch, DrawGraph_CopyStretch),
@@ -397,8 +476,8 @@ HLL_LIBRARY(DrawGraph,
//HLL_EXPORT(CopyRotateYFixR, DrawGraph_CopyRotateYFixR),
//HLL_EXPORT(CopyRotateYFixLUseAMap, DrawGraph_CopyRotateYFixLUseAMap),
//HLL_EXPORT(CopyRotateYFixRUseAMap, DrawGraph_CopyRotateYFixRUseAMap),
//HLL_EXPORT(CopyRotateX, DrawGraph_CopyRotateX),
//HLL_EXPORT(CopyRotateXUseAMap, DrawGraph_CopyRotateXUseAMap),
HLL_EXPORT(CopyRotateX, DrawGraph_CopyRotateX),
HLL_EXPORT(CopyRotateXUseAMap, DrawGraph_CopyRotateXUseAMap),
//HLL_EXPORT(CopyRotateXFixU, DrawGraph_CopyRotateXFixU),
//HLL_EXPORT(CopyRotateXFixD, DrawGraph_CopyRotateXFixD),
//HLL_EXPORT(CopyRotateXFixUUseAMap, DrawGraph_CopyRotateXFixUUseAMap),
+105
View File
@@ -0,0 +1,105 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include "system4/string.h"
#include "hll.h"
#include "movie.h"
#include "sact.h"
static struct movie_context *mc;
static void DrawMovie_Release(void)
{
if (mc)
movie_free(mc);
mc = NULL;
}
static bool DrawMovie_Load(struct string *filename)
{
if (mc)
movie_free(mc);
mc = movie_load(filename->text);
return !!mc;
}
static bool DrawMovie_Run(void)
{
if (!mc)
return false;
return movie_play(mc);
}
static bool DrawMovie_Draw(int sprite)
{
if (!mc)
return false;
struct sact_sprite *sp = sact_try_get_sprite(sprite);
if (!sp)
return false;
return movie_draw(mc, sp);
}
static bool DrawMovie_SetVolume(int volume)
{
if (!mc)
return false;
return movie_set_volume(mc, volume);
}
static bool DrawMovie_IsEnd(void)
{
if (!mc)
return true;
return movie_is_end(mc);
}
static int DrawMovie_GetCount(void)
{
if (!mc)
return 0;
return movie_get_position(mc);
}
static void DrawMovie2_UpdateVolume(void)
{
// Do nothing, as SetInnerVolume immediately takes effect.
}
HLL_LIBRARY(DrawMovie,
HLL_EXPORT(Release, DrawMovie_Release),
HLL_EXPORT(Load, DrawMovie_Load),
HLL_EXPORT(Run, DrawMovie_Run),
HLL_EXPORT(Draw, DrawMovie_Draw),
HLL_EXPORT(SetVolume, DrawMovie_SetVolume),
HLL_EXPORT(IsEnd, DrawMovie_IsEnd),
HLL_EXPORT(GetCount, DrawMovie_GetCount)
);
HLL_LIBRARY(DrawMovie2,
HLL_EXPORT(Release, DrawMovie_Release),
HLL_EXPORT(Load, DrawMovie_Load),
HLL_EXPORT(Run, DrawMovie_Run),
HLL_EXPORT(Draw, DrawMovie_Draw),
HLL_EXPORT(SetVolume, DrawMovie_SetVolume),
HLL_EXPORT(SetInnerVolume, DrawMovie_SetVolume),
HLL_EXPORT(UpdateVolume, DrawMovie2_UpdateVolume),
HLL_EXPORT(IsEnd, DrawMovie_IsEnd),
HLL_EXPORT(GetCount, DrawMovie_GetCount)
);
+1
View File
@@ -18,6 +18,7 @@
#include "hll.h"
#include "gfx/gfx.h"
#include "gfx/font.h"
#include "sact.h"
static int size = 20;
+5 -5
View File
@@ -52,9 +52,9 @@ static int File_Open(struct string *filename, int type)
}
char *path = unix_path(filename->text);
current_file = fopen(path, mode);
current_file = file_open_utf8(path, mode);
if (!current_file) {
WARNING("Failed to open file '%s': %s", path, strerror(errno));
WARNING("Failed to open file '%s': %s", display_utf0(path), strerror(errno));
}
free(path);
@@ -157,11 +157,11 @@ struct tagSaveDate {
static int File_GetTime(struct string *filename, struct page **page)
{
struct stat s;
ustat s;
char *path = unix_path(filename->text);
union vm_value *date = (*page)->values;
if (stat(path, &s) < 0) {
if (stat_utf8(path, &s) < 0) {
WARNING("stat failed: %s", strerror(errno));
free(path);
return 0;
@@ -175,7 +175,7 @@ static int File_GetTime(struct string *filename, struct page **page)
}
date[0].i = tm->tm_year + 1900;
date[1].i = tm->tm_mon;
date[1].i = tm->tm_mon + 1;
date[2].i = tm->tm_mday;
date[3].i = tm->tm_hour;
date[4].i = tm->tm_min;
+189
View File
@@ -0,0 +1,189 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "system4.h"
#include "system4/file.h"
#include "system4/string.h"
#include "little_endian.h"
#include "hll.h"
#include "xsystem4.h"
static FILE *current_file = NULL;
static bool file2_open(struct string *filename, const char *mode)
{
if (current_file) {
WARNING("Previously opened file wasn't closed");
fclose(current_file);
}
char *path = unix_path(filename->text);
current_file = file_open_utf8(path, mode);
if (!current_file) {
WARNING("Failed to open file '%s': %s", display_utf0(path), strerror(errno));
}
free(path);
return !!current_file;
}
static bool file2_write(const void *ptr, size_t size)
{
if (!current_file) {
WARNING("File2.Write* called, but no open file");
return false;
}
if (fwrite(ptr, size, 1, current_file) != 1) {
WARNING("fwrite failed: %s", strerror(errno));
return false;
}
return true;
}
static bool file2_read(void *dst, size_t size)
{
if (!current_file) {
WARNING("File2.Read* called, but no open file");
return false;
}
if (fread(dst, size, 1, current_file) != 1) {
WARNING("fread failed: %s", strerror(errno));
return false;
}
return true;
}
static bool File2_OpenForWrite(struct string *filename)
{
return file2_open(filename, "wb");
}
static bool File2_OpenForRead(struct string *filename)
{
return file2_open(filename, "rb");
}
static bool File2_Close(void)
{
if (!current_file) {
VM_ERROR("File2.Close called, but no open file");
}
int r = !fclose(current_file);
current_file = NULL;
return r;
}
static bool File2_WriteByte(int data)
{
uint8_t b = data;
return file2_write(&b, 1);
}
static bool File2_WriteInt(int data)
{
uint8_t b[4];
LittleEndian_putDW(b, 0, data);
return file2_write(b, 4);
}
static bool File2_WriteFloat(float data)
{
uint8_t b[4];
union {
uint32_t i;
float f;
} cast;
cast.f = data;
LittleEndian_putDW(b, 0, cast.i);
return file2_write(b, 4);
}
static bool File2_WriteString(struct string *str)
{
return file2_write(str->text, str->size+1);
}
static bool File2_ReadByte(int *data)
{
uint8_t b;
if (!file2_read(&b, 1))
return false;
*data = b;
return true;
}
static bool File2_ReadInt(int *data)
{
uint8_t b[4];
if (!file2_read(b, 4))
return false;
*data = LittleEndian_getDW(b, 0);
return true;
}
static bool File2_ReadFloat(float *data)
{
uint8_t b[4];
union {
uint32_t i;
float f;
} cast;
if (!file2_read(b, 4))
return false;
cast.i = LittleEndian_getDW(b, 0);
*data = cast.f;
return true;
}
static bool File2_ReadString(struct string **str)
{
char b;
struct string *s = make_string("", 0);
while (true) {
if (!file2_read((uint8_t*)&b, 1)) {
free_string(s);
return false;
}
if (!b)
break;
string_append_cstr(&s, &b, 1);
}
if (*str)
free_string(*str);
*str = s;
return true;
}
HLL_LIBRARY(File2,
HLL_EXPORT(OpenForWrite, File2_OpenForWrite),
HLL_EXPORT(OpenForRead, File2_OpenForRead),
HLL_EXPORT(Close, File2_Close),
HLL_EXPORT(WriteByte, File2_WriteByte),
HLL_EXPORT(WriteInt, File2_WriteInt),
HLL_EXPORT(WriteFloat, File2_WriteFloat),
HLL_EXPORT(WriteString, File2_WriteString),
HLL_EXPORT(ReadByte, File2_ReadByte),
HLL_EXPORT(ReadInt, File2_ReadInt),
HLL_EXPORT(ReadFloat, File2_ReadFloat),
HLL_EXPORT(ReadString, File2_ReadString)
);
+16 -14
View File
@@ -53,26 +53,29 @@ static bool get_file_list(struct string *folder_name, struct page **out, bool fo
{
char *dir_name = unix_path(folder_name->text);
DIR *d = opendir(dir_name);
UDIR *d = opendir_utf8(dir_name);
if (!d) {
WARNING("opendir(\"%s\"): %s", dir_name, strerror(errno));
goto error;
WARNING("opendir(\"%s\"): %s", display_utf0(dir_name), strerror(errno));
free(dir_name);
return false;
}
struct string **names = NULL;
int nr_names = 0;
struct dirent *dir;
while ((dir = readdir(d)) != NULL) {
if (dir->d_name[0] == '.')
char *d_name;
while ((d_name = readdir_utf8(d)) != NULL) {
if (d_name[0] == '.') {
free(d_name);
continue;
}
char *utf8_path = path_join(dir_name, dir->d_name);
char *utf8_path = path_join(dir_name, d_name);
char *sjis_path = utf2sjis(utf8_path, 0);
struct stat s;
if (stat(utf8_path, &s) < 0) {
WARNING("stat(\"%s\"): %s", utf8_path, strerror(errno));
ustat s;
if (stat_utf8(utf8_path, &s) < 0) {
WARNING("stat(\"%s\"): %s", display_utf0(utf8_path), strerror(errno));
goto loop_next;
}
if (folders) {
@@ -91,7 +94,10 @@ static bool get_file_list(struct string *folder_name, struct page **out, bool fo
loop_next:
free(utf8_path);
free(sjis_path);
free(d_name);
}
closedir_utf8(d);
free(dir_name);
union vm_value dim = { .i = nr_names };
struct page *page = alloc_array(1, &dim, AIN_ARRAY_STRING, 0, false);
@@ -105,10 +111,6 @@ static bool get_file_list(struct string *folder_name, struct page **out, bool fo
}
*out = page;
return true;
error:
free(dir_name);
return false;
}
static bool FileOperation_GetFileList(struct string *folder_name, struct page **out)
+84
View File
@@ -0,0 +1,84 @@
/* Copyright (C) 2022 kichikuou <KichikuouChrome@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <cglm/cglm.h>
#include "gfx/gfx.h"
#include "hll.h"
#include "sact.h"
struct fill_angele_shader {
struct shader s;
GLint center;
GLint start_angle;
GLint angle;
GLint color;
};
static struct fill_angele_shader shader;
static void load_shader(void)
{
gfx_load_shader(&shader.s, "shaders/render.v.glsl", "shaders/fill_angle.f.glsl");
shader.center = glGetUniformLocation(shader.s.program, "center");
shader.start_angle = glGetUniformLocation(shader.s.program, "start_angle");
shader.angle = glGetUniformLocation(shader.s.program, "angle");
shader.color = glGetUniformLocation(shader.s.program, "color");
}
static bool FillAngle_FillAngleAMAP(int sprite, int center_x, int center_y, int start_angle, int angle, int alpha)
{
struct sact_sprite *sp = sact_try_get_sprite(sprite);
if (!sp)
return false;
struct texture *dst = sprite_get_texture(sp);
float w = dst->w;
float h = dst->h;
if (!shader.s.program)
load_shader();
glUseProgram(shader.s.program);
glUniform2f(shader.center, center_x / w, center_y / h);
glUniform1f(shader.start_angle, glm_rad(start_angle));
glUniform1f(shader.angle, glm_rad(angle));
glUniform4f(shader.color, 0, 0, 0, alpha / 255.0);
glUseProgram(0);
mat4 mw_transform = MAT4(
w, 0, 0, 0,
0, h, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
mat4 wv_transform = WV_TRANSFORM(dst->w, dst->h);
GLuint fbo = gfx_set_framebuffer(GL_DRAW_FRAMEBUFFER, dst, 0, 0, dst->w, dst->h);
struct gfx_render_job job = {
.shader = &shader.s,
.texture = 0,
.world_transform = mw_transform[0],
.view_transform = wv_transform[0],
.data = NULL
};
glBlendFuncSeparate(GL_ZERO, GL_ONE, GL_ONE, GL_ZERO);
gfx_render(&job);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
gfx_reset_framebuffer(GL_DRAW_FRAMEBUFFER, fbo);
return true;
}
HLL_LIBRARY(FillAngle,
HLL_EXPORT(FillAngleAMAP, FillAngle_FillAngleAMAP)
);
+967
View File
@@ -0,0 +1,967 @@
/* Copyright (C) 2019 Nunuhara Cabbage <nunuhara@haniwa.technology>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://gnu.org/licenses/>.
*/
#include <string.h>
#include "gfx/gfx.h"
#include "parts.h"
#include "hll.h"
static void GUIEngine_ModuleInit(void)
{
gfx_init();
PE_Init();
}
static void GUIEngine_ModuleFini(void)
{
}
//static void GUIEngine_Release(int PartsNumber);
//static void GUIEngine_ReleaseAll(ref array<int> EraseNumberList);
//static void GUIEngine_ReleaseAllWithoutSystem(ref array<int> EraseNumberList);
//static void GUIEngine_SetDelegateIndex(int PartsNumber, int DelegateIndex);
//static int GUIEngine_GetFreeNumber(void)
//static bool GUIEngine_IsExist(int PartsNumber);
//static void GUIEngine_PushController(void);
//static void GUIEngine_PopController(ref array<int> EraseNumberList);
//static void GUIEngine_UpdateComponent(possibly_unused int passed_time)
//static void GUIEngine_BeginInput(void);
//static void GUIEngine_EndInput(void);
//static void GUIEngine_UpdateInputState(int PassedTime);
//static void GUIEngine_UpdateParts(int PassedTime, bool IsSkip, bool MessageWindowShow);
//static void GUIEngine_SetFocus(int PartsNumber);
//static bool GUIEngine_IsFocus(int PartsNumber);
//static void GUIEngine_StopSoundWithoutSystemSound(void);
HLL_WARN_UNIMPLEMENTED(, void, GUIEngine, StopSoundWithoutSystemSound);
//static void GUIEngine_ReleaseMessage(void);
HLL_QUIET_UNIMPLEMENTED(, void, GUIEngine, ReleaseMessage);
//static void GUIEngine_PopMessage(void);
//static int GUIEngine_GetMessagePartsNumber(void);
//static int GUIEngine_GetMessageDelegateIndex(void);
//static int GUIEngine_GetDelegateIndex(int PartsNumber);
//static int GUIEngine_GetMessageType(void);
HLL_QUIET_UNIMPLEMENTED(0, int, GUIEngine, GetMessageType);
//static int GUIEngine_GetMessageVariableCount(void);
//static int GUIEngine_GetMessageVariableType(int MessageVariableIndex);
//static int GUIEngine_GetMessageVariableInt(int MessageVariableIndex);
//static float GUIEngine_GetMessageVariableFloat(int MessageVariableIndex);
//static bool GUIEngine_GetMessageVariableBool(int MessageVariableIndex);
//static void GUIEngine_GetMessageVariableString(int MessageVariableIndex, ref string String);
//static void GUIEngine_SetButtonPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetButtonZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetButtonX(int PartsNumber);
//static int GUIEngine_GetButtonY(int PartsNumber);
//static int GUIEngine_GetButtonZ(int PartsNumber);
//static void GUIEngine_SetButtonWidth(int PartsNumber, int Width);
//static void GUIEngine_SetButtonHeight(int PartsNumber, int Height);
//static int GUIEngine_GetButtonWidth(int PartsNumber);
//static int GUIEngine_GetButtonHeight(int PartsNumber);
//static void GUIEngine_SetButtonShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsButtonShow(int PartsNumber);
//static void GUIEngine_SetButtonDrag(int PartsNumber, bool Drag);
//static bool GUIEngine_IsButtonDrag(int PartsNumber);
//static void GUIEngine_SetButtonEnable(int PartsNumber, bool Enable);
//static bool GUIEngine_IsButtonEnable(int PartsNumber);
//static void GUIEngine_SetButtonPixelDecide(int PartsNumber, bool PixelDecide);
//static bool GUIEngine_IsButtonPixelDecide(int PartsNumber);
//static void GUIEngine_SetButtonR(int PartsNumber, int Red);
//static void GUIEngine_SetButtonG(int PartsNumber, int Green);
//static void GUIEngine_SetButtonB(int PartsNumber, int Blue);
//static int GUIEngine_GetButtonR(int PartsNumber);
//static int GUIEngine_GetButtonG(int PartsNumber);
//static int GUIEngine_GetButtonB(int PartsNumber);
//static void GUIEngine_SetButtonFontProperty(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight);
//static void GUIEngine_GetButtonFontProperty(int PartsNumber, ref int Type, ref int Size, ref int R, ref int G, ref int B, ref float BoldWeight, ref int EdgeR, ref int EdgeG, ref int EdgeB, ref float EdgeWeight);
//static void GUIEngine_SetButtonOnCursorSoundNumber(int PartsNumber, int SoundNumber);
//static void GUIEngine_SetButtonClickSoundNumber(int PartsNumber, int SoundNumber);
//static int GUIEngine_GetButtonOnCursorSoundNumber(int PartsNumber);
//static int GUIEngine_GetButtonClickSoundNumber(int PartsNumber);
//static void GUIEngine_SetButtonCGName(int PartsNumber, string Name);
//static void GUIEngine_GetButtonCGName(int PartsNumber, ref string Name);
//static void GUIEngine_SetButtonText(int PartsNumber, string pIText);
//static void GUIEngine_GetButtonText(int PartsNumber, ref string pIText);
//static void GUIEngine_SetCGBoxPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetCGBoxZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetCGBoxX(int PartsNumber);
//static int GUIEngine_GetCGBoxY(int PartsNumber);
//static int GUIEngine_GetCGBoxZ(int PartsNumber);
//static void GUIEngine_SetCGBoxWidth(int PartsNumber, int Width);
//static void GUIEngine_SetCGBoxHeight(int PartsNumber, int Height);
//static int GUIEngine_GetCGBoxWidth(int PartsNumber);
//static int GUIEngine_GetCGBoxHeight(int PartsNumber);
//static void GUIEngine_SetCGBoxAlpha(int PartsNumber, int Alpha);
//static int GUIEngine_GetCGBoxAlpha(int PartsNumber);
//static void GUIEngine_SetCGBoxViewMode(int PartsNumber, int ViewMode);
//static int GUIEngine_GetCGBoxViewMode(int PartsNumber);
//static void GUIEngine_SetCGBoxShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsCGBoxShow(int PartsNumber);
//static void GUIEngine_SetCGBoxDrag(int PartsNumber, bool Drag);
//static bool GUIEngine_IsCGBoxDrag(int PartsNumber);
//static void GUIEngine_SetCGBoxCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetCGBoxCGName(int PartsNumber, ref string pIName);
//static void GUIEngine_SetCGBoxAddR(int PartsNumber, int Red);
//static void GUIEngine_SetCGBoxAddG(int PartsNumber, int Green);
//static void GUIEngine_SetCGBoxAddB(int PartsNumber, int Blue);
//static int GUIEngine_GetCGBoxAddR(int PartsNumber);
//static int GUIEngine_GetCGBoxAddG(int PartsNumber);
//static int GUIEngine_GetCGBoxAddB(int PartsNumber);
//static void GUIEngine_SetCGBoxMulR(int PartsNumber, int Red);
//static void GUIEngine_SetCGBoxMulG(int PartsNumber, int Green);
//static void GUIEngine_SetCGBoxMulB(int PartsNumber, int Blue);
//static int GUIEngine_GetCGBoxMulR(int PartsNumber);
//static int GUIEngine_GetCGBoxMulG(int PartsNumber);
//static int GUIEngine_GetCGBoxMulB(int PartsNumber);
//static void GUIEngine_SetCheckBoxPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetCheckBoxZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetCheckBoxX(int PartsNumber);
//static int GUIEngine_GetCheckBoxY(int PartsNumber);
//static int GUIEngine_GetCheckBoxZ(int PartsNumber);
//static void GUIEngine_SetCheckBoxWidth(int PartsNumber, int Width);
//static void GUIEngine_SetCheckBoxHeight(int PartsNumber, int Height);
//static int GUIEngine_GetCheckBoxWidth(int PartsNumber);
//static int GUIEngine_GetCheckBoxHeight(int PartsNumber);
//static void GUIEngine_SetCheckBoxShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsCheckBoxShow(int PartsNumber);
//static void GUIEngine_SetCheckBoxDrag(int PartsNumber, bool Drag);
//static bool GUIEngine_IsCheckBoxDrag(int PartsNumber);
//static void GUIEngine_CheckBoxChecked(int PartsNumber, bool Check);
//static bool GUIEngine_IsCheckBoxChecked(int PartsNumber);
//static void GUIEngine_SetCheckBoxR(int PartsNumber, int Red);
//static void GUIEngine_SetCheckBoxG(int PartsNumber, int Green);
//static void GUIEngine_SetCheckBoxB(int PartsNumber, int Blue);
//static int GUIEngine_GetCheckBoxR(int PartsNumber);
//static int GUIEngine_GetCheckBoxG(int PartsNumber);
//static int GUIEngine_GetCheckBoxB(int PartsNumber);
//static void GUIEngine_SetCheckBoxFontProperty(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight);
//static void GUIEngine_GetCheckBoxFontProperty(int PartsNumber, ref int Type, ref int Size, ref int R, ref int G, ref int B, ref float BoldWeight, ref int EdgeR, ref int EdgeG, ref int EdgeB, ref float EdgeWeight);
//static void GUIEngine_SetCheckBoxOnCursorSoundNumber(int PartsNumber, int SoundNumber);
//static void GUIEngine_SetCheckBoxClickSoundNumber(int PartsNumber, int SoundNumber);
//static int GUIEngine_GetCheckBoxOnCursorSoundNumber(int PartsNumber);
//static int GUIEngine_GetCheckBoxClickSoundNumber(int PartsNumber);
//static void GUIEngine_SetCheckBoxCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetCheckBoxCGName(int PartsNumber, ref string pIName);
//static void GUIEngine_SetCheckBoxText(int PartsNumber, string pIName);
//static void GUIEngine_GetCheckBoxText(int PartsNumber, ref string pIName);
//static void GUIEngine_SetLabelPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetLabelZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetLabelX(int PartsNumber);
//static int GUIEngine_GetLabelY(int PartsNumber);
//static int GUIEngine_GetLabelZ(int PartsNumber);
//static void GUIEngine_SetLabelWidth(int PartsNumber, int Width);
//static void GUIEngine_SetLabelHeight(int PartsNumber, int Height);
//static int GUIEngine_GetLabelWidth(int PartsNumber);
//static int GUIEngine_GetLabelHeight(int PartsNumber);
//static void GUIEngine_SetLabelAlpha(int PartsNumber, int Alpha);
//static int GUIEngine_GetLabelAlpha(int PartsNumber);
//static void GUIEngine_SetLabelShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsLabelShow(int PartsNumber);
//static void GUIEngine_SetLabelDrag(int PartsNumber, bool Drag);
//static bool GUIEngine_IsLabelDrag(int PartsNumber);
//static void GUIEngine_SetLabelClip(int PartsNumber, bool Clip);
//static bool GUIEngine_IsLabelClip(int PartsNumber);
//static void GUIEngine_SetLabelText(int PartsNumber, string pIText);
//static void GUIEngine_GetLabelText(int PartsNumber, ref string pIText);
//static void GUIEngine_SetLabelFontProperty(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight);
//static void GUIEngine_GetLabelFontProperty(int PartsNumber, ref int Type, ref int Size, ref int R, ref int G, ref int B, ref float BoldWeight, ref int EdgeR, ref int EdgeG, ref int EdgeB, ref float EdgeWeight);
//static void GUIEngine_SetVScrollbarPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetVScrollbarZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetVScrollbarX(int PartsNumber);
//static int GUIEngine_GetVScrollbarY(int PartsNumber);
//static int GUIEngine_GetVScrollbarZ(int PartsNumber);
//static void GUIEngine_SetVScrollbarShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsVScrollbarShow(int PartsNumber);
//static void GUIEngine_SetVScrollbarOnCursorSoundNumber(int PartsNumber, int SoundNumber);
//static void GUIEngine_SetVScrollbarClickSoundNumber(int PartsNumber, int SoundNumber);
//static int GUIEngine_GetVScrollbarOnCursorSoundNumber(int PartsNumber);
//static int GUIEngine_GetVScrollbarClickSoundNumber(int PartsNumber);
//static void GUIEngine_SetVScrollbarWidth(int PartsNumber, int Width);
//static void GUIEngine_SetVScrollbarHeight(int PartsNumber, int Height);
//static void GUIEngine_SetVScrollbarUpHeight(int PartsNumber, int Height);
//static void GUIEngine_SetVScrollbarDownHeight(int PartsNumber, int Height);
//static int GUIEngine_GetVScrollbarWidth(int PartsNumber);
//static int GUIEngine_GetVScrollbarHeight(int PartsNumber);
//static int GUIEngine_GetVScrollbarUpHeight(int PartsNumber);
//static int GUIEngine_GetVScrollbarDownHeight(int PartsNumber);
//static void GUIEngine_SetVScrollbarTotalSize(int PartsNumber, int Size);
//static void GUIEngine_SetVScrollbarViewSize(int PartsNumber, int Size);
//static void GUIEngine_SetVScrollbarScrollPos(int PartsNumber, int Pos);
//static void GUIEngine_SetVScrollbarMoveSizeByButton(int PartsNumber, int Size);
//static int GUIEngine_GetVScrollbarTotalSize(int PartsNumber);
//static int GUIEngine_GetVScrollbarViewSize(int PartsNumber);
//static int GUIEngine_GetVScrollbarScrollPos(int PartsNumber);
//static int GUIEngine_GetVScrollbarMoveSizeByButton(int PartsNumber);
//static void GUIEngine_SetVScrollbarCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetVScrollbarCGName(int PartsNumber, ref string pIName);
//static void GUIEngine_SetHScrollbarPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetHScrollbarZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetHScrollbarX(int PartsNumber);
//static int GUIEngine_GetHScrollbarY(int PartsNumber);
//static int GUIEngine_GetHScrollbarZ(int PartsNumber);
//static void GUIEngine_SetHScrollbarShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsHScrollbarShow(int PartsNumber);
//static void GUIEngine_SetHScrollbarOnCursorSoundNumber(int PartsNumber, int SoundNumber);
//static void GUIEngine_SetHScrollbarClickSoundNumber(int PartsNumber, int SoundNumber);
//static int GUIEngine_GetHScrollbarOnCursorSoundNumber(int PartsNumber);
//static int GUIEngine_GetHScrollbarClickSoundNumber(int PartsNumber);
//static void GUIEngine_SetHScrollbarWidth(int PartsNumber, int Width);
//static void GUIEngine_SetHScrollbarHeight(int PartsNumber, int Height);
//static void GUIEngine_SetHScrollbarLeftWidth(int PartsNumber, int Width);
//static void GUIEngine_SetHScrollbarRightWidth(int PartsNumber, int Width);
//static int GUIEngine_GetHScrollbarWidth(int PartsNumber);
//static int GUIEngine_GetHScrollbarHeight(int PartsNumber);
//static int GUIEngine_GetHScrollbarLeftWidth(int PartsNumber);
//static int GUIEngine_GetHScrollbarRightWidth(int PartsNumber);
//static void GUIEngine_SetHScrollbarTotalSize(int PartsNumber, int Size);
//static void GUIEngine_SetHScrollbarViewSize(int PartsNumber, int Size);
//static void GUIEngine_SetHScrollbarScrollPos(int PartsNumber, int Pos);
//static void GUIEngine_SetHScrollbarMoveSizeByButton(int PartsNumber, int Size);
//static int GUIEngine_GetHScrollbarTotalSize(int PartsNumber);
//static int GUIEngine_GetHScrollbarViewSize(int PartsNumber);
//static int GUIEngine_GetHScrollbarScrollPos(int PartsNumber);
//static int GUIEngine_GetHScrollbarMoveSizeByButton(int PartsNumber);
//static void GUIEngine_SetHScrollbarCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetHScrollbarCGName(int PartsNumber, ref string pIName);
//static void GUIEngine_SetTextBoxPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetTextBoxZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetTextBoxX(int PartsNumber);
//static int GUIEngine_GetTextBoxY(int PartsNumber);
//static int GUIEngine_GetTextBoxZ(int PartsNumber);
//static void GUIEngine_SetTextBoxWidth(int PartsNumber, int Width);
//static void GUIEngine_SetTextBoxHeight(int PartsNumber, int Height);
//static int GUIEngine_GetTextBoxWidth(int PartsNumber);
//static int GUIEngine_GetTextBoxHeight(int PartsNumber);
//static void GUIEngine_SetTextBoxShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsTextBoxShow(int PartsNumber);
//static void GUIEngine_SetTextBoxFontProperty(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight);
//static void GUIEngine_GetTextBoxFontProperty(int PartsNumber, ref int Type, ref int Size, ref int R, ref int G, ref int B, ref float BoldWeight, ref int EdgeR, ref int EdgeG, ref int EdgeB, ref float EdgeWeight);
//static void GUIEngine_SetTextBoxText(int PartsNumber, string pIText);
//static void GUIEngine_GetTextBoxText(int PartsNumber, ref string pIText);
//static void GUIEngine_SetTextBoxMaxTextLength(int PartsNumber, int Length);
//static int GUIEngine_GetTextBoxMaxTextLength(int PartsNumber);
//static void GUIEngine_SetTextBoxSelectR(int PartsNumber, int Red);
//static void GUIEngine_SetTextBoxSelectG(int PartsNumber, int Green);
//static void GUIEngine_SetTextBoxSelectB(int PartsNumber, int Blue);
//static int GUIEngine_GetTextBoxSelectR(int PartsNumber);
//static int GUIEngine_GetTextBoxSelectG(int PartsNumber);
//static int GUIEngine_GetTextBoxSelectB(int PartsNumber);
//static void GUIEngine_SetTextBoxCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetTextBoxCGName(int PartsNumber, ref string pIName);
//static void GUIEngine_SetListBoxPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetListBoxZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetListBoxX(int PartsNumber);
//static int GUIEngine_GetListBoxY(int PartsNumber);
//static int GUIEngine_GetListBoxZ(int PartsNumber);
//static void GUIEngine_SetListBoxWidth(int PartsNumber, int Width);
//static void GUIEngine_SetListBoxLineHeight(int PartsNumber, int Height);
//static void GUIEngine_SetListBoxHeight(int PartsNumber, int Height);
//static int GUIEngine_GetListBoxWidth(int PartsNumber);
//static int GUIEngine_GetListBoxLineHeight(int PartsNumber);
//static int GUIEngine_GetListBoxHeight(int PartsNumber);
//static void GUIEngine_SetListBoxWidthMargin(int PartsNumber, int Margin);
//static void GUIEngine_SetListBoxHeightMargin(int PartsNumber, int Margin);
//static int GUIEngine_GetListBoxWidthMargin(int PartsNumber);
//static int GUIEngine_GetListBoxHeightMargin(int PartsNumber);
//static void GUIEngine_SetListBoxShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsListBoxShow(int PartsNumber);
//static void GUIEngine_SetListBoxCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetListBoxCGName(int PartsNumber, ref string pIName);
//static void GUIEngine_SetListBoxScrollPos(int PartsNumber, int Pos);
//static int GUIEngine_GetListBoxScrollPos(int PartsNumber);
//static void GUIEngine_AddListBoxItem(int PartsNumber, string pIItem);
//static void GUIEngine_SetListBoxItem(int PartsNumber, int Index, string pIItem);
//static int GUIEngine_GetListBoxItemCount(int PartsNumber);
//static void GUIEngine_GetListBoxItem(int PartsNumber, int Index, ref string pIItem);
//static void GUIEngine_EraseListBoxItem(int PartsNumber, int Index);
//static void GUIEngine_ClearListBoxItem(int PartsNumber);
//static void GUIEngine_SetListBoxFontProperty(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight);
//static void GUIEngine_GetListBoxFontProperty(int PartsNumber, ref int Type, ref int Size, ref int R, ref int G, ref int B, ref float BoldWeight, ref int EdgeR, ref int EdgeG, ref int EdgeB, ref float EdgeWeight);
//static void GUIEngine_SetListBoxSelectIndex(int PartsNumber, int Index);
//static int GUIEngine_GetListBoxSelectIndex(int PartsNumber);
//static void GUIEngine_SetComboBoxPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetComboBoxZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetComboBoxX(int PartsNumber);
//static int GUIEngine_GetComboBoxY(int PartsNumber);
//static int GUIEngine_GetComboBoxZ(int PartsNumber);
//static void GUIEngine_SetComboBoxWidth(int PartsNumber, int Width);
//static void GUIEngine_SetComboBoxHeight(int PartsNumber, int Height);
//static int GUIEngine_GetComboBoxWidth(int PartsNumber);
//static int GUIEngine_GetComboBoxHeight(int PartsNumber);
//static void GUIEngine_SetComboBoxTextWidthMargin(int PartsNumber, int Margin);
//static void GUIEngine_SetComboBoxTextHeightMargin(int PartsNumber, int Margin);
//static int GUIEngine_GetComboBoxTextWidthMargin(int PartsNumber);
//static int GUIEngine_GetComboBoxTextHeightMargin(int PartsNumber);
//static void GUIEngine_SetComboBoxShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsComboBoxShow(int PartsNumber);
//static void GUIEngine_SetComboBoxCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetComboBoxCGName(int PartsNumber, ref string pIName);
//static void GUIEngine_SetComboBoxText(int PartsNumber, string pIItem);
//static void GUIEngine_GetComboBoxText(int PartsNumber, ref string pIItem);
//static void GUIEngine_SetComboBoxFontProperty(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight);
//static void GUIEngine_GetComboBoxFontProperty(int PartsNumber, ref int Type, ref int Size, ref int R, ref int G, ref int B, ref float BoldWeight, ref int EdgeR, ref int EdgeG, ref int EdgeB, ref float EdgeWeight);
//static void GUIEngine_SetMultiTextBoxPos(int PartsNumber, int PosX, int PosY);
//static void GUIEngine_SetMultiTextBoxZ(int PartsNumber, int PosZ);
//static int GUIEngine_GetMultiTextBoxX(int PartsNumber);
//static int GUIEngine_GetMultiTextBoxY(int PartsNumber);
//static int GUIEngine_GetMultiTextBoxZ(int PartsNumber);
//static void GUIEngine_SetMultiTextBoxWidth(int PartsNumber, int Width);
//static void GUIEngine_SetMultiTextBoxHeight(int PartsNumber, int Height);
//static int GUIEngine_GetMultiTextBoxWidth(int PartsNumber);
//static int GUIEngine_GetMultiTextBoxHeight(int PartsNumber);
//static void GUIEngine_SetMultiTextBoxShow(int PartsNumber, bool Show);
//static bool GUIEngine_IsMultiTextBoxShow(int PartsNumber);
//static void GUIEngine_SetMultiTextBoxFontProperty(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight);
//static void GUIEngine_GetMultiTextBoxFontProperty(int PartsNumber, ref int Type, ref int Size, ref int R, ref int G, ref int B, ref float BoldWeight, ref int EdgeR, ref int EdgeG, ref int EdgeB, ref float EdgeWeight);
//static void GUIEngine_SetMultiTextBoxText(int PartsNumber, string Text);
//static void GUIEngine_GetMultiTextBoxText(int PartsNumber, ref string Text);
//static void GUIEngine_SetMultiTextBoxMaxTextLength(int PartsNumber, int Length);
//static int GUIEngine_GetMultiTextBoxMaxTextLength(int PartsNumber);
//static void GUIEngine_SetMultiTextBoxSelectR(int PartsNumber, int Red);
//static void GUIEngine_SetMultiTextBoxSelectG(int PartsNumber, int Green);
//static void GUIEngine_SetMultiTextBoxSelectB(int PartsNumber, int Blue);
//static int GUIEngine_GetMultiTextBoxSelectR(int PartsNumber);
//static int GUIEngine_GetMultiTextBoxSelectG(int PartsNumber);
//static int GUIEngine_GetMultiTextBoxSelectB(int PartsNumber);
//static void GUIEngine_SetMultiTextBoxCGName(int PartsNumber, string pIName);
//static void GUIEngine_GetMultiTextBoxCGName(int PartsNumber, ref string pIName);
//static bool GUIEngine_Parts_SetPartsCG(int PartsNumber, string pCGName, int SpriteDeform, int State);
//static void GUIEngine_Parts_GetPartsCGName(int PartsNumber, ref string pCGName, int State);
//static bool GUIEngine_Parts_SetPartsCGSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetLoopCG(int PartsNumber, string pCGName, int StartNo, int NumofCG, int TimePerCG, int State);
//static bool GUIEngine_Parts_SetLoopCGSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetText(int PartsNumber, string pIText, int State);
//static bool GUIEngine_Parts_AddPartsText(int PartsNumber, string pIText, int State);
//static bool GUIEngine_Parts_DeletePartsTopTextLine(int PartsNumber, int State);
//static bool GUIEngine_Parts_SetPartsTextSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static void GUIEngine_Parts_SetPartsTextHighlight(int PartsNumber, int Start, int Length, int nR, int nG, int nB, int State);
//static void GUIEngine_Parts_AddPartsTextHighlight(int PartsNumber, int Start, int Length, int nR, int nG, int nB, int State);
//static void GUIEngine_Parts_ClearPartsTextHighlight(int PartsNumber, int State);
//static void GUIEngine_Parts_SetPartsTextCountReturn(int PartsNumber, bool Count, int State);
//static bool GUIEngine_Parts_GetPartsTextCountReturn(int PartsNumber, int State);
//static bool GUIEngine_Parts_SetFont(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight, int State);
//static bool GUIEngine_Parts_SetPartsFontType(int PartsNumber, int Type, int State);
//static bool GUIEngine_Parts_SetPartsFontSize(int PartsNumber, int Size, int State);
//static bool GUIEngine_Parts_SetPartsFontColor(int PartsNumber, int R, int G, int B, int State);
//static bool GUIEngine_Parts_SetPartsFontBoldWeight(int PartsNumber, float BoldWeight, int State);
//static bool GUIEngine_Parts_SetPartsFontEdgeColor(int PartsNumber, int R, int G, int B, int State);
//static bool GUIEngine_Parts_SetPartsFontEdgeWeight(int PartsNumber, float EdgeWeight, int State);
//static bool GUIEngine_Parts_SetTextCharSpace(int PartsNumber, int CharSpace, int State);
//static bool GUIEngine_Parts_SetTextLineSpace(int PartsNumber, int LineSpace, int State);
//static bool GUIEngine_Parts_SetHGaugeCG(int PartsNumber, string pCGName, int State);
//static bool GUIEngine_Parts_SetHGaugeRate(int PartsNumber, float Numerator, float Denominator, int State);
//static bool GUIEngine_Parts_SetVGaugeCG(int PartsNumber, string pCGName, int State);
//static bool GUIEngine_Parts_SetVGaugeRate(int PartsNumber, float Numerator, float Denominator, int State);
//static bool GUIEngine_Parts_SetHGaugeSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetVGaugeSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetNumeralCG(int PartsNumber, string pBaseCGName, int State);
//static bool GUIEngine_Parts_SetNumeralLinkedCGNumberWidthWidthList(int PartsNumber, string pCGName, int Width0, int Width1, int Width2, int Width3, int Width4, int Width5, int Width6, int Width7, int Width8, int Width9, int WidthMinus, int WidthComma, int State);
//static bool GUIEngine_Parts_SetNumeralFont(int PartsNumber, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight, bool FullPitch, int State);
//static bool GUIEngine_Parts_SetNumeralNumber(int PartsNumber, int Number, int State);
//static bool GUIEngine_Parts_SetNumeralShowComma(int PartsNumber, bool ShowComma, int State);
//static bool GUIEngine_Parts_SetNumeralSpace(int PartsNumber, int NumeralSpace, int State);
//static bool GUIEngine_Parts_SetNumeralLength(int PartsNumber, int Length, int State);
//static bool GUIEngine_Parts_SetNumeralSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetPartsRectangleDetectionSize(int PartsNumber, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetPartsRectangleDetectionSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetPartsCGDetectionSize(int PartsNumber, string pCGName, int State);
//static bool GUIEngine_Parts_SetPartsCGDetectionSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetPartsFlat(int PartsNumber, string pIFileName, int State);
//static bool GUIEngine_Parts_IsPartsFlatEnd(int PartsNumber, int State);
//static int GUIEngine_Parts_GetPartsFlatCurrentFrameNumber(int PartsNumber, int State);
//static bool GUIEngine_Parts_BackPartsFlatBeginFrame(int PartsNumber, int State);
//static bool GUIEngine_Parts_StepPartsFlatFinalFrame(int PartsNumber, int State);
//static bool GUIEngine_Parts_SetPartsFlatSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_SetPartsFlatAndStop(int PartsNumber, string pIFileName, int State);
//static bool GUIEngine_Parts_StopPartsFlat(int PartsNumber, int State);
//static bool GUIEngine_Parts_StartPartsFlat(int PartsNumber, int State);
//static bool GUIEngine_Parts_GoFramePartsFlat(int PartsNumber, int CurrentFrame, int State);
//static int GUIEngine_Parts_GetPartsFlatEndFrame(int PartsNumber, int State);
//static bool GUIEngine_Parts_ExistsFlatFile(string pIFileName);
//static bool GUIEngine_Parts_ClearPartsConstructionProcess(int PartsNumber, int State);
//static bool GUIEngine_Parts_AddCreateToPartsConstructionProcess(int PartsNumber, int nWidth, int nHeight, int State);
//static bool GUIEngine_Parts_AddCreatePixelOnlyToPartsConstructionProcess(int PartsNumber, int nWidth, int nHeight, int State);
//static bool GUIEngine_Parts_AddCreateCGToProcess(int PartsNumber, string pICGName, int State);
//static bool GUIEngine_Parts_AddFillToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB, int State);
//static bool GUIEngine_Parts_AddFillAlphaColorToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB, int nA, int State);
//static bool GUIEngine_Parts_AddFillAMapToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nAlpha, int State);
//static bool GUIEngine_Parts_AddFillWithAlphaToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB, int nA, int State);
//static bool GUIEngine_Parts_AddFillGradationHorizonToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nTopR, int nTopG, int nTopB, int nBottomR, int nBottomG, int nBottomB, int State);
//static bool GUIEngine_Parts_AddDrawRectToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB, int State);
//static bool GUIEngine_Parts_AddDrawCutCGToPartsConstructionProcess(int PartsNumber, string pICGName, int DestX, int DestY, int DestWidth, int DestHeight, int SrcX, int SrcY, int SrcWidth, int SrcHeight, int InterpolationType, int State);
//static bool GUIEngine_Parts_AddCopyCutCGToPartsConstructionProcess(int PartsNumber, string pICGName, int DestX, int DestY, int DestWidth, int DestHeight, int SrcX, int SrcY, int SrcWidth, int SrcHeight, int InterpolationType, int State);
//static bool GUIEngine_Parts_AddGrayFilterToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, bool FullSize, int State);
//static bool GUIEngine_Parts_AddAddFilterToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB, bool FullSize, int State);
//static bool GUIEngine_Parts_AddMulFilterToPartsConstructionProcess(int PartsNumber, int nX, int nY, int nWidth, int nHeight, int nR, int nG, int nB, bool FullSize, int State);
//static bool GUIEngine_Parts_AddDrawLineToPartsConstructionProcess(int PartsNumber, int nX1, int nY1, int nX2, int nY2, int nR, int nG, int nB, int nA, int State);
//static bool GUIEngine_Parts_BuildPartsConstructionProcess(int PartsNumber, int State);
//static bool GUIEngine_Parts_AddDrawTextToPartsConstructionProcess(int PartsNumber, int nX, int nY, string pIText, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight, int CharSpace, int LineSpace, int State);
//static bool GUIEngine_Parts_AddCopyTextToPartsConstructionProcess(int PartsNumber, int nX, int nY, string pIText, int Type, int Size, int R, int G, int B, float BoldWeight, int EdgeR, int EdgeG, int EdgeB, float EdgeWeight, int CharSpace, int LineSpace, int State);
//static bool GUIEngine_Parts_SetPartsConstructionSurfaceArea(int PartsNumber, int X, int Y, int Width, int Height, int State);
//static bool GUIEngine_Parts_CreateParts3DLayerPluginID(int PartsNumber, int State);
//static int GUIEngine_Parts_GetParts3DLayerPluginID(int PartsNumber, int State);
//static bool GUIEngine_Parts_ReleaseParts3DLayerPluginID(int PartsNumber, int State);
//static void GUIEngine_Parts_SetPos(int PartsNumber, int X, int Y);
//static void GUIEngine_Parts_SetZ(int PartsNumber, int Z);
//static void GUIEngine_Parts_SetShow(int PartsNumber, bool Show);
//static void GUIEngine_Parts_SetAlpha(int PartsNumber, int Alpha);
//static void GUIEngine_Parts_SetPartsDrawFilter(int PartsNumber, int DrawFilter);
//static void GUIEngine_Parts_SetPassCursor(int PartsNumber, bool Pass);
//static void GUIEngine_Parts_SetClickable(int PartsNumber, bool Clickable);
//static void GUIEngine_Parts_SetSpeedupRateByMessageSkip(int PartsNumber, int Rate);
//static void GUIEngine_Parts_SetResetTimerByChangeInputStatus(int PartsNumber, bool Reset, int State);
//static void GUIEngine_Parts_SetAddColor(int PartsNumber, int nR, int nG, int nB);
//static void GUIEngine_Parts_SetMultiplyColor(int PartsNumber, int nR, int nG, int nB);
//static void GUIEngine_Parts_SetDrag(int PartsNumber, bool Drag);
//static void GUIEngine_Parts_SetPartsOriginPosMode(int PartsNumber, int OriginPosMode);
//static void GUIEngine_Parts_SetParentPartsNumber(int PartsNumber, int ParentPartsNumber);
//static void GUIEngine_Parts_SetInputState(int PartsNumber, int State);
//static void GUIEngine_Parts_SetOnCursorShowLinkPartsNumber(int PartsNumber, int LinkPartsNumber);
//static void GUIEngine_Parts_SetPartsMessageWindowShowLink(int PartsNumber, bool MessageWindowShowLink);
//static void GUIEngine_Parts_SetSoundNumber(int PartsNumber, int SoundNumber, int State);
//static void GUIEngine_Parts_SetClickMissSoundNumber(int SoundNumber);
//static void GUIEngine_Parts_SetPartsMagX(int PartsNumber, float MagX);
//static void GUIEngine_Parts_SetPartsMagY(int PartsNumber, float MagY);
//static void GUIEngine_Parts_SetPartsRotateX(int PartsNumber, float RotateX);
//static void GUIEngine_Parts_SetPartsRotateY(int PartsNumber, float RotateY);
//static void GUIEngine_Parts_SetPartsRotateZ(int PartsNumber, float RotateZ);
//static void GUIEngine_Parts_SetPartsAlphaClipperPartsNumber(int PartsNumber, int AlphaClipperPartsNumber);
//static void GUIEngine_Parts_SetPartsPixelDecide(int PartsNumber, bool PixelDecide);
//static int GUIEngine_Parts_GetPartsX(int PartsNumber);
//static int GUIEngine_Parts_GetPartsY(int PartsNumber);
//static int GUIEngine_Parts_GetPartsZ(int PartsNumber);
//static bool GUIEngine_Parts_GetPartsShow(int PartsNumber);
//static int GUIEngine_Parts_GetPartsAlpha(int PartsNumber);
//static int GUIEngine_Parts_GetPartsDrawFilter(int PartsNumber);
//static bool GUIEngine_Parts_GetPartsPassCursor(int PartsNumber);
//static bool GUIEngine_Parts_GetPartsClickable(int PartsNumber);
//static int GUIEngine_Parts_GetPartsSpeedupRateByMessageSkip(int PartsNumber);
//static bool GUIEngine_Parts_GetResetTimerByChangeInputStatus(int PartsNumber, int State);
//static void GUIEngine_Parts_GetAddColor(int PartsNumber, ref int nR, ref int nG, ref int nB);
//static void GUIEngine_Parts_GetMultiplyColor(int PartsNumber, ref int nR, ref int nG, ref int nB);
//static bool GUIEngine_Parts_GetPartsDrag(int PartsNumber);
//static int GUIEngine_Parts_GetPartsOriginPosMode(int PartsNumber);
//static int GUIEngine_Parts_GetParentPartsNumber(int PartsNumber);
//static int GUIEngine_Parts_GetInputState(int PartsNumber);
//static int GUIEngine_Parts_GetOnCursorShowLinkPartsNumber(int PartsNumber);
//static bool GUIEngine_Parts_GetPartsMessageWindowShowLink(int PartsNumber);
//static int GUIEngine_Parts_GetSoundNumber(int PartsNumber, int State);
//static int GUIEngine_Parts_GetClickMissSoundNumber(void);
//static float GUIEngine_Parts_GetPartsMagX(int PartsNumber);
//static float GUIEngine_Parts_GetPartsMagY(int PartsNumber);
//static float GUIEngine_Parts_GetPartsRotateX(int PartsNumber);
//static float GUIEngine_Parts_GetPartsRotateY(int PartsNumber);
//static float GUIEngine_Parts_GetPartsRotateZ(int PartsNumber);
//static int GUIEngine_Parts_GetPartsAlphaClipperPartsNumber(int PartsNumber);
//static bool GUIEngine_Parts_IsPartsPixelDecide(int PartsNumber);
//static int GUIEngine_Parts_GetPartsUpperLeftPosX(int PartsNumber, int State);
//static int GUIEngine_Parts_GetPartsUpperLeftPosY(int PartsNumber, int State);
//static int GUIEngine_Parts_GetPartsWidth(int PartsNumber, int State);
//static int GUIEngine_Parts_GetPartsHeight(int PartsNumber, int State);
//static void GUIEngine_Parts_AddMotionPos(int PartsNumber, int BeginX, int BeginY, int EndX, int EndY, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionAlpha(int PartsNumber, int BeginAlpha, int EndAlpha, int BeginTime, int EndTime, string pICurveName);
//static bool GUIEngine_Parts_AddMotionCG(int PartsNumber, string BaseCGName, int BeginCGNumber, int NumofCG, int BeginTime, int EndTime, string pICurveName);
//static bool GUIEngine_Parts_AddMotionCGTermination(int PartsNumber, int EndTime);
//static void GUIEngine_Parts_AddMotionHGaugeRate(int PartsNumber, float BeginNumerator, float BeginDenominator, float EndNumerator, float EndDenominator, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionVGaugeRate(int PartsNumber, float BeginNumerator, float BeginDenominator, float EndNumerator, float EndDenominator, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionNumeralNumber(int PartsNumber, int BeginNumber, int EndNumber, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionMagX(int PartsNumber, float BeginMagX, float EndMagX, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionMagY(int PartsNumber, float BeginMagY, float EndMagY, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionRotateX(int PartsNumber, float BeginRotateX, float EndRotateX, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionRotateY(int PartsNumber, float BeginRotateY, float EndRotateY, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionRotateZ(int PartsNumber, float BeginRotateZ, float EndRotateZ, int BeginTime, int EndTime, string pICurveName);
//static void GUIEngine_Parts_AddMotionVibrationSize(int PartsNumber, int BeginWidth, int BeginHeight, int BeginTime, int EndTime);
//static void GUIEngine_Parts_AddWholeMotionVibrationSize(int BeginWidth, int BeginHeight, int BeginTime, int EndTime);
//static void GUIEngine_Parts_AddMotionSound(int SoundNumber, int BeginTime);
//static bool GUIEngine_Parts_IsCursorIn(int PartsNumber, int MouseX, int MouseY, int State);
//static bool GUIEngine_Parts_SetThumbnailReductionSize(int ReductionSize);
//static bool GUIEngine_Parts_SetThumbnailMode(bool Mode);
//static int GUIEngine_GetClickNumber(void);
//static void GUIEngine_Parts_BeginMotion(void);
//static void GUIEngine_Parts_EndMotion(void);
//static bool GUIEngine_Parts_IsMotion(void);
//static void GUIEngine_Parts_SeekEndMotion(void);
//static void GUIEngine_Parts_UpdateMotionTime(int Time, bool Skip);
//static bool GUIEngine_Save(ref array<int> SaveDataBuffer);
//static bool GUIEngine_SaveWithoutHideParts(ref array<int> SaveDataBuffer);
//static bool GUIEngine_Load(ref array<int> SaveDataBuffer);
HLL_LIBRARY(GUIEngine,
HLL_EXPORT(_ModuleInit, GUIEngine_ModuleInit),
HLL_EXPORT(_ModuleFini, GUIEngine_ModuleFini),
HLL_EXPORT(Release, PE_ReleaseParts),
HLL_EXPORT(ReleaseAll, PE_ReleaseAllParts),
HLL_EXPORT(ReleaseAllWithoutSystem, PE_ReleaseAllPartsWithoutSystem),
HLL_EXPORT(SetDelegateIndex, PE_SetDelegateIndex),
HLL_EXPORT(GetFreeNumber, PE_GetFreeNumber),
HLL_EXPORT(IsExist, PE_IsExist),
HLL_TODO_EXPORT(PushController, GUIEngine_PushController),
HLL_TODO_EXPORT(PopController, GUIEngine_PopController),
HLL_EXPORT(UpdateComponent, PE_UpdateComponent),
HLL_EXPORT(BeginInput, PE_BeginInput),
HLL_EXPORT(EndInput, PE_EndInput),
HLL_EXPORT(UpdateInputState, PE_UpdateInputState),
HLL_EXPORT(UpdateParts, PE_UpdateParts),
HLL_TODO_EXPORT(SetFocus, GUIEngine_SetFocus),
HLL_TODO_EXPORT(IsFocus, GUIEngine_IsFocus),
HLL_EXPORT(StopSoundWithoutSystemSound, GUIEngine_StopSoundWithoutSystemSound),
HLL_EXPORT(ReleaseMessage, GUIEngine_ReleaseMessage),
HLL_TODO_EXPORT(PopMessage, GUIEngine_PopMessage),
HLL_TODO_EXPORT(GetMessagePartsNumber, GUIEngine_GetMessagePartsNumber),
HLL_TODO_EXPORT(GetMessageDelegateIndex, GUIEngine_GetMessageDelegateIndex),
HLL_EXPORT(GetDelegateIndex, PE_GetDelegateIndex),
HLL_EXPORT(GetMessageType, GUIEngine_GetMessageType),
HLL_TODO_EXPORT(GetMessageVariableCount, GUIEngine_GetMessageVariableCount),
HLL_TODO_EXPORT(GetMessageVariableType, GUIEngine_GetMessageVariableType),
HLL_TODO_EXPORT(GetMessageVariableInt, GUIEngine_GetMessageVariableInt),
HLL_TODO_EXPORT(GetMessageVariableFloat, GUIEngine_GetMessageVariableFloat),
HLL_TODO_EXPORT(GetMessageVariableBool, GUIEngine_GetMessageVariableBool),
HLL_TODO_EXPORT(GetMessageVariableString, GUIEngine_GetMessageVariableString),
HLL_TODO_EXPORT(SetButtonPos, GUIEngine_SetButtonPos),
HLL_TODO_EXPORT(SetButtonZ, GUIEngine_SetButtonZ),
HLL_TODO_EXPORT(GetButtonX, GUIEngine_GetButtonX),
HLL_TODO_EXPORT(GetButtonY, GUIEngine_GetButtonY),
HLL_TODO_EXPORT(GetButtonZ, GUIEngine_GetButtonZ),
HLL_TODO_EXPORT(SetButtonWidth, GUIEngine_SetButtonWidth),
HLL_TODO_EXPORT(SetButtonHeight, GUIEngine_SetButtonHeight),
HLL_TODO_EXPORT(GetButtonWidth, GUIEngine_GetButtonWidth),
HLL_TODO_EXPORT(GetButtonHeight, GUIEngine_GetButtonHeight),
HLL_TODO_EXPORT(SetButtonShow, GUIEngine_SetButtonShow),
HLL_TODO_EXPORT(IsButtonShow, GUIEngine_IsButtonShow),
HLL_TODO_EXPORT(SetButtonDrag, GUIEngine_SetButtonDrag),
HLL_TODO_EXPORT(IsButtonDrag, GUIEngine_IsButtonDrag),
HLL_TODO_EXPORT(SetButtonEnable, GUIEngine_SetButtonEnable),
HLL_TODO_EXPORT(IsButtonEnable, GUIEngine_IsButtonEnable),
HLL_TODO_EXPORT(SetButtonPixelDecide, GUIEngine_SetButtonPixelDecide),
HLL_TODO_EXPORT(IsButtonPixelDecide, GUIEngine_IsButtonPixelDecide),
HLL_TODO_EXPORT(SetButtonR, GUIEngine_SetButtonR),
HLL_TODO_EXPORT(SetButtonG, GUIEngine_SetButtonG),
HLL_TODO_EXPORT(SetButtonB, GUIEngine_SetButtonB),
HLL_TODO_EXPORT(GetButtonR, GUIEngine_GetButtonR),
HLL_TODO_EXPORT(GetButtonG, GUIEngine_GetButtonG),
HLL_TODO_EXPORT(GetButtonB, GUIEngine_GetButtonB),
HLL_TODO_EXPORT(SetButtonFontProperty, GUIEngine_SetButtonFontProperty),
HLL_TODO_EXPORT(GetButtonFontProperty, GUIEngine_GetButtonFontProperty),
HLL_TODO_EXPORT(SetButtonOnCursorSoundNumber, GUIEngine_SetButtonOnCursorSoundNumber),
HLL_TODO_EXPORT(SetButtonClickSoundNumber, GUIEngine_SetButtonClickSoundNumber),
HLL_TODO_EXPORT(GetButtonOnCursorSoundNumber, GUIEngine_GetButtonOnCursorSoundNumber),
HLL_TODO_EXPORT(GetButtonClickSoundNumber, GUIEngine_GetButtonClickSoundNumber),
HLL_TODO_EXPORT(SetButtonCGName, GUIEngine_SetButtonCGName),
HLL_TODO_EXPORT(GetButtonCGName, GUIEngine_GetButtonCGName),
HLL_TODO_EXPORT(SetButtonText, GUIEngine_SetButtonText),
HLL_TODO_EXPORT(GetButtonText, GUIEngine_GetButtonText),
HLL_TODO_EXPORT(SetCGBoxPos, GUIEngine_SetCGBoxPos),
HLL_TODO_EXPORT(SetCGBoxZ, GUIEngine_SetCGBoxZ),
HLL_TODO_EXPORT(GetCGBoxX, GUIEngine_GetCGBoxX),
HLL_TODO_EXPORT(GetCGBoxY, GUIEngine_GetCGBoxY),
HLL_TODO_EXPORT(GetCGBoxZ, GUIEngine_GetCGBoxZ),
HLL_TODO_EXPORT(SetCGBoxWidth, GUIEngine_SetCGBoxWidth),
HLL_TODO_EXPORT(SetCGBoxHeight, GUIEngine_SetCGBoxHeight),
HLL_TODO_EXPORT(GetCGBoxWidth, GUIEngine_GetCGBoxWidth),
HLL_TODO_EXPORT(GetCGBoxHeight, GUIEngine_GetCGBoxHeight),
HLL_TODO_EXPORT(SetCGBoxAlpha, GUIEngine_SetCGBoxAlpha),
HLL_TODO_EXPORT(GetCGBoxAlpha, GUIEngine_GetCGBoxAlpha),
HLL_TODO_EXPORT(SetCGBoxViewMode, GUIEngine_SetCGBoxViewMode),
HLL_TODO_EXPORT(GetCGBoxViewMode, GUIEngine_GetCGBoxViewMode),
HLL_TODO_EXPORT(SetCGBoxShow, GUIEngine_SetCGBoxShow),
HLL_TODO_EXPORT(IsCGBoxShow, GUIEngine_IsCGBoxShow),
HLL_TODO_EXPORT(SetCGBoxDrag, GUIEngine_SetCGBoxDrag),
HLL_TODO_EXPORT(IsCGBoxDrag, GUIEngine_IsCGBoxDrag),
HLL_TODO_EXPORT(SetCGBoxCGName, GUIEngine_SetCGBoxCGName),
HLL_TODO_EXPORT(GetCGBoxCGName, GUIEngine_GetCGBoxCGName),
HLL_TODO_EXPORT(SetCGBoxAddR, GUIEngine_SetCGBoxAddR),
HLL_TODO_EXPORT(SetCGBoxAddG, GUIEngine_SetCGBoxAddG),
HLL_TODO_EXPORT(SetCGBoxAddB, GUIEngine_SetCGBoxAddB),
HLL_TODO_EXPORT(GetCGBoxAddR, GUIEngine_GetCGBoxAddR),
HLL_TODO_EXPORT(GetCGBoxAddG, GUIEngine_GetCGBoxAddG),
HLL_TODO_EXPORT(GetCGBoxAddB, GUIEngine_GetCGBoxAddB),
HLL_TODO_EXPORT(SetCGBoxMulR, GUIEngine_SetCGBoxMulR),
HLL_TODO_EXPORT(SetCGBoxMulG, GUIEngine_SetCGBoxMulG),
HLL_TODO_EXPORT(SetCGBoxMulB, GUIEngine_SetCGBoxMulB),
HLL_TODO_EXPORT(GetCGBoxMulR, GUIEngine_GetCGBoxMulR),
HLL_TODO_EXPORT(GetCGBoxMulG, GUIEngine_GetCGBoxMulG),
HLL_TODO_EXPORT(GetCGBoxMulB, GUIEngine_GetCGBoxMulB),
HLL_TODO_EXPORT(SetCheckBoxPos, GUIEngine_SetCheckBoxPos),
HLL_TODO_EXPORT(SetCheckBoxZ, GUIEngine_SetCheckBoxZ),
HLL_TODO_EXPORT(GetCheckBoxX, GUIEngine_GetCheckBoxX),
HLL_TODO_EXPORT(GetCheckBoxY, GUIEngine_GetCheckBoxY),
HLL_TODO_EXPORT(GetCheckBoxZ, GUIEngine_GetCheckBoxZ),
HLL_TODO_EXPORT(SetCheckBoxWidth, GUIEngine_SetCheckBoxWidth),
HLL_TODO_EXPORT(SetCheckBoxHeight, GUIEngine_SetCheckBoxHeight),
HLL_TODO_EXPORT(GetCheckBoxWidth, GUIEngine_GetCheckBoxWidth),
HLL_TODO_EXPORT(GetCheckBoxHeight, GUIEngine_GetCheckBoxHeight),
HLL_TODO_EXPORT(SetCheckBoxShow, GUIEngine_SetCheckBoxShow),
HLL_TODO_EXPORT(IsCheckBoxShow, GUIEngine_IsCheckBoxShow),
HLL_TODO_EXPORT(SetCheckBoxDrag, GUIEngine_SetCheckBoxDrag),
HLL_TODO_EXPORT(IsCheckBoxDrag, GUIEngine_IsCheckBoxDrag),
HLL_TODO_EXPORT(CheckBoxChecked, GUIEngine_CheckBoxChecked),
HLL_TODO_EXPORT(IsCheckBoxChecked, GUIEngine_IsCheckBoxChecked),
HLL_TODO_EXPORT(SetCheckBoxR, GUIEngine_SetCheckBoxR),
HLL_TODO_EXPORT(SetCheckBoxG, GUIEngine_SetCheckBoxG),
HLL_TODO_EXPORT(SetCheckBoxB, GUIEngine_SetCheckBoxB),
HLL_TODO_EXPORT(GetCheckBoxR, GUIEngine_GetCheckBoxR),
HLL_TODO_EXPORT(GetCheckBoxG, GUIEngine_GetCheckBoxG),
HLL_TODO_EXPORT(GetCheckBoxB, GUIEngine_GetCheckBoxB),
HLL_TODO_EXPORT(SetCheckBoxFontProperty, GUIEngine_SetCheckBoxFontProperty),
HLL_TODO_EXPORT(GetCheckBoxFontProperty, GUIEngine_GetCheckBoxFontProperty),
HLL_TODO_EXPORT(SetCheckBoxOnCursorSoundNumber, GUIEngine_SetCheckBoxOnCursorSoundNumber),
HLL_TODO_EXPORT(SetCheckBoxClickSoundNumber, GUIEngine_SetCheckBoxClickSoundNumber),
HLL_TODO_EXPORT(GetCheckBoxOnCursorSoundNumber, GUIEngine_GetCheckBoxOnCursorSoundNumber),
HLL_TODO_EXPORT(GetCheckBoxClickSoundNumber, GUIEngine_GetCheckBoxClickSoundNumber),
HLL_TODO_EXPORT(SetCheckBoxCGName, GUIEngine_SetCheckBoxCGName),
HLL_TODO_EXPORT(GetCheckBoxCGName, GUIEngine_GetCheckBoxCGName),
HLL_TODO_EXPORT(SetCheckBoxText, GUIEngine_SetCheckBoxText),
HLL_TODO_EXPORT(GetCheckBoxText, GUIEngine_GetCheckBoxText),
HLL_TODO_EXPORT(SetLabelPos, GUIEngine_SetLabelPos),
HLL_TODO_EXPORT(SetLabelZ, GUIEngine_SetLabelZ),
HLL_TODO_EXPORT(GetLabelX, GUIEngine_GetLabelX),
HLL_TODO_EXPORT(GetLabelY, GUIEngine_GetLabelY),
HLL_TODO_EXPORT(GetLabelZ, GUIEngine_GetLabelZ),
HLL_TODO_EXPORT(SetLabelWidth, GUIEngine_SetLabelWidth),
HLL_TODO_EXPORT(SetLabelHeight, GUIEngine_SetLabelHeight),
HLL_TODO_EXPORT(GetLabelWidth, GUIEngine_GetLabelWidth),
HLL_TODO_EXPORT(GetLabelHeight, GUIEngine_GetLabelHeight),
HLL_TODO_EXPORT(SetLabelAlpha, GUIEngine_SetLabelAlpha),
HLL_TODO_EXPORT(GetLabelAlpha, GUIEngine_GetLabelAlpha),
HLL_TODO_EXPORT(SetLabelShow, GUIEngine_SetLabelShow),
HLL_TODO_EXPORT(IsLabelShow, GUIEngine_IsLabelShow),
HLL_TODO_EXPORT(SetLabelDrag, GUIEngine_SetLabelDrag),
HLL_TODO_EXPORT(IsLabelDrag, GUIEngine_IsLabelDrag),
HLL_TODO_EXPORT(SetLabelClip, GUIEngine_SetLabelClip),
HLL_TODO_EXPORT(IsLabelClip, GUIEngine_IsLabelClip),
HLL_TODO_EXPORT(SetLabelText, GUIEngine_SetLabelText),
HLL_TODO_EXPORT(GetLabelText, GUIEngine_GetLabelText),
HLL_TODO_EXPORT(SetLabelFontProperty, GUIEngine_SetLabelFontProperty),
HLL_TODO_EXPORT(GetLabelFontProperty, GUIEngine_GetLabelFontProperty),
HLL_TODO_EXPORT(SetVScrollbarPos, GUIEngine_SetVScrollbarPos),
HLL_TODO_EXPORT(SetVScrollbarZ, GUIEngine_SetVScrollbarZ),
HLL_TODO_EXPORT(GetVScrollbarX, GUIEngine_GetVScrollbarX),
HLL_TODO_EXPORT(GetVScrollbarY, GUIEngine_GetVScrollbarY),
HLL_TODO_EXPORT(GetVScrollbarZ, GUIEngine_GetVScrollbarZ),
HLL_TODO_EXPORT(SetVScrollbarShow, GUIEngine_SetVScrollbarShow),
HLL_TODO_EXPORT(IsVScrollbarShow, GUIEngine_IsVScrollbarShow),
HLL_TODO_EXPORT(SetVScrollbarOnCursorSoundNumber, GUIEngine_SetVScrollbarOnCursorSoundNumber),
HLL_TODO_EXPORT(SetVScrollbarClickSoundNumber, GUIEngine_SetVScrollbarClickSoundNumber),
HLL_TODO_EXPORT(GetVScrollbarOnCursorSoundNumber, GUIEngine_GetVScrollbarOnCursorSoundNumber),
HLL_TODO_EXPORT(GetVScrollbarClickSoundNumber, GUIEngine_GetVScrollbarClickSoundNumber),
HLL_TODO_EXPORT(SetVScrollbarWidth, GUIEngine_SetVScrollbarWidth),
HLL_TODO_EXPORT(SetVScrollbarHeight, GUIEngine_SetVScrollbarHeight),
HLL_TODO_EXPORT(SetVScrollbarUpHeight, GUIEngine_SetVScrollbarUpHeight),
HLL_TODO_EXPORT(SetVScrollbarDownHeight, GUIEngine_SetVScrollbarDownHeight),
HLL_TODO_EXPORT(GetVScrollbarWidth, GUIEngine_GetVScrollbarWidth),
HLL_TODO_EXPORT(GetVScrollbarHeight, GUIEngine_GetVScrollbarHeight),
HLL_TODO_EXPORT(GetVScrollbarUpHeight, GUIEngine_GetVScrollbarUpHeight),
HLL_TODO_EXPORT(GetVScrollbarDownHeight, GUIEngine_GetVScrollbarDownHeight),
HLL_TODO_EXPORT(SetVScrollbarTotalSize, GUIEngine_SetVScrollbarTotalSize),
HLL_TODO_EXPORT(SetVScrollbarViewSize, GUIEngine_SetVScrollbarViewSize),
HLL_TODO_EXPORT(SetVScrollbarScrollPos, GUIEngine_SetVScrollbarScrollPos),
HLL_TODO_EXPORT(SetVScrollbarMoveSizeByButton, GUIEngine_SetVScrollbarMoveSizeByButton),
HLL_TODO_EXPORT(GetVScrollbarTotalSize, GUIEngine_GetVScrollbarTotalSize),
HLL_TODO_EXPORT(GetVScrollbarViewSize, GUIEngine_GetVScrollbarViewSize),
HLL_TODO_EXPORT(GetVScrollbarScrollPos, GUIEngine_GetVScrollbarScrollPos),
HLL_TODO_EXPORT(GetVScrollbarMoveSizeByButton, GUIEngine_GetVScrollbarMoveSizeByButton),
HLL_TODO_EXPORT(SetVScrollbarCGName, GUIEngine_SetVScrollbarCGName),
HLL_TODO_EXPORT(GetVScrollbarCGName, GUIEngine_GetVScrollbarCGName),
HLL_TODO_EXPORT(SetHScrollbarPos, GUIEngine_SetHScrollbarPos),
HLL_TODO_EXPORT(SetHScrollbarZ, GUIEngine_SetHScrollbarZ),
HLL_TODO_EXPORT(GetHScrollbarX, GUIEngine_GetHScrollbarX),
HLL_TODO_EXPORT(GetHScrollbarY, GUIEngine_GetHScrollbarY),
HLL_TODO_EXPORT(GetHScrollbarZ, GUIEngine_GetHScrollbarZ),
HLL_TODO_EXPORT(SetHScrollbarShow, GUIEngine_SetHScrollbarShow),
HLL_TODO_EXPORT(IsHScrollbarShow, GUIEngine_IsHScrollbarShow),
HLL_TODO_EXPORT(SetHScrollbarOnCursorSoundNumber, GUIEngine_SetHScrollbarOnCursorSoundNumber),
HLL_TODO_EXPORT(SetHScrollbarClickSoundNumber, GUIEngine_SetHScrollbarClickSoundNumber),
HLL_TODO_EXPORT(GetHScrollbarOnCursorSoundNumber, GUIEngine_GetHScrollbarOnCursorSoundNumber),
HLL_TODO_EXPORT(GetHScrollbarClickSoundNumber, GUIEngine_GetHScrollbarClickSoundNumber),
HLL_TODO_EXPORT(SetHScrollbarWidth, GUIEngine_SetHScrollbarWidth),
HLL_TODO_EXPORT(SetHScrollbarHeight, GUIEngine_SetHScrollbarHeight),
HLL_TODO_EXPORT(SetHScrollbarLeftWidth, GUIEngine_SetHScrollbarLeftWidth),
HLL_TODO_EXPORT(SetHScrollbarRightWidth, GUIEngine_SetHScrollbarRightWidth),
HLL_TODO_EXPORT(GetHScrollbarWidth, GUIEngine_GetHScrollbarWidth),
HLL_TODO_EXPORT(GetHScrollbarHeight, GUIEngine_GetHScrollbarHeight),
HLL_TODO_EXPORT(GetHScrollbarLeftWidth, GUIEngine_GetHScrollbarLeftWidth),
HLL_TODO_EXPORT(GetHScrollbarRightWidth, GUIEngine_GetHScrollbarRightWidth),
HLL_TODO_EXPORT(SetHScrollbarTotalSize, GUIEngine_SetHScrollbarTotalSize),
HLL_TODO_EXPORT(SetHScrollbarViewSize, GUIEngine_SetHScrollbarViewSize),
HLL_TODO_EXPORT(SetHScrollbarScrollPos, GUIEngine_SetHScrollbarScrollPos),
HLL_TODO_EXPORT(SetHScrollbarMoveSizeByButton, GUIEngine_SetHScrollbarMoveSizeByButton),
HLL_TODO_EXPORT(GetHScrollbarTotalSize, GUIEngine_GetHScrollbarTotalSize),
HLL_TODO_EXPORT(GetHScrollbarViewSize, GUIEngine_GetHScrollbarViewSize),
HLL_TODO_EXPORT(GetHScrollbarScrollPos, GUIEngine_GetHScrollbarScrollPos),
HLL_TODO_EXPORT(GetHScrollbarMoveSizeByButton, GUIEngine_GetHScrollbarMoveSizeByButton),
HLL_TODO_EXPORT(SetHScrollbarCGName, GUIEngine_SetHScrollbarCGName),
HLL_TODO_EXPORT(GetHScrollbarCGName, GUIEngine_GetHScrollbarCGName),
HLL_TODO_EXPORT(SetTextBoxPos, GUIEngine_SetTextBoxPos),
HLL_TODO_EXPORT(SetTextBoxZ, GUIEngine_SetTextBoxZ),
HLL_TODO_EXPORT(GetTextBoxX, GUIEngine_GetTextBoxX),
HLL_TODO_EXPORT(GetTextBoxY, GUIEngine_GetTextBoxY),
HLL_TODO_EXPORT(GetTextBoxZ, GUIEngine_GetTextBoxZ),
HLL_TODO_EXPORT(SetTextBoxWidth, GUIEngine_SetTextBoxWidth),
HLL_TODO_EXPORT(SetTextBoxHeight, GUIEngine_SetTextBoxHeight),
HLL_TODO_EXPORT(GetTextBoxWidth, GUIEngine_GetTextBoxWidth),
HLL_TODO_EXPORT(GetTextBoxHeight, GUIEngine_GetTextBoxHeight),
HLL_TODO_EXPORT(SetTextBoxShow, GUIEngine_SetTextBoxShow),
HLL_TODO_EXPORT(IsTextBoxShow, GUIEngine_IsTextBoxShow),
HLL_TODO_EXPORT(SetTextBoxFontProperty, GUIEngine_SetTextBoxFontProperty),
HLL_TODO_EXPORT(GetTextBoxFontProperty, GUIEngine_GetTextBoxFontProperty),
HLL_TODO_EXPORT(SetTextBoxText, GUIEngine_SetTextBoxText),
HLL_TODO_EXPORT(GetTextBoxText, GUIEngine_GetTextBoxText),
HLL_TODO_EXPORT(SetTextBoxMaxTextLength, GUIEngine_SetTextBoxMaxTextLength),
HLL_TODO_EXPORT(GetTextBoxMaxTextLength, GUIEngine_GetTextBoxMaxTextLength),
HLL_TODO_EXPORT(SetTextBoxSelectR, GUIEngine_SetTextBoxSelectR),
HLL_TODO_EXPORT(SetTextBoxSelectG, GUIEngine_SetTextBoxSelectG),
HLL_TODO_EXPORT(SetTextBoxSelectB, GUIEngine_SetTextBoxSelectB),
HLL_TODO_EXPORT(GetTextBoxSelectR, GUIEngine_GetTextBoxSelectR),
HLL_TODO_EXPORT(GetTextBoxSelectG, GUIEngine_GetTextBoxSelectG),
HLL_TODO_EXPORT(GetTextBoxSelectB, GUIEngine_GetTextBoxSelectB),
HLL_TODO_EXPORT(SetTextBoxCGName, GUIEngine_SetTextBoxCGName),
HLL_TODO_EXPORT(GetTextBoxCGName, GUIEngine_GetTextBoxCGName),
HLL_TODO_EXPORT(SetListBoxPos, GUIEngine_SetListBoxPos),
HLL_TODO_EXPORT(SetListBoxZ, GUIEngine_SetListBoxZ),
HLL_TODO_EXPORT(GetListBoxX, GUIEngine_GetListBoxX),
HLL_TODO_EXPORT(GetListBoxY, GUIEngine_GetListBoxY),
HLL_TODO_EXPORT(GetListBoxZ, GUIEngine_GetListBoxZ),
HLL_TODO_EXPORT(SetListBoxWidth, GUIEngine_SetListBoxWidth),
HLL_TODO_EXPORT(SetListBoxLineHeight, GUIEngine_SetListBoxLineHeight),
HLL_TODO_EXPORT(SetListBoxHeight, GUIEngine_SetListBoxHeight),
HLL_TODO_EXPORT(GetListBoxWidth, GUIEngine_GetListBoxWidth),
HLL_TODO_EXPORT(GetListBoxLineHeight, GUIEngine_GetListBoxLineHeight),
HLL_TODO_EXPORT(GetListBoxHeight, GUIEngine_GetListBoxHeight),
HLL_TODO_EXPORT(SetListBoxWidthMargin, GUIEngine_SetListBoxWidthMargin),
HLL_TODO_EXPORT(SetListBoxHeightMargin, GUIEngine_SetListBoxHeightMargin),
HLL_TODO_EXPORT(GetListBoxWidthMargin, GUIEngine_GetListBoxWidthMargin),
HLL_TODO_EXPORT(GetListBoxHeightMargin, GUIEngine_GetListBoxHeightMargin),
HLL_TODO_EXPORT(SetListBoxShow, GUIEngine_SetListBoxShow),
HLL_TODO_EXPORT(IsListBoxShow, GUIEngine_IsListBoxShow),
HLL_TODO_EXPORT(SetListBoxCGName, GUIEngine_SetListBoxCGName),
HLL_TODO_EXPORT(GetListBoxCGName, GUIEngine_GetListBoxCGName),
HLL_TODO_EXPORT(SetListBoxScrollPos, GUIEngine_SetListBoxScrollPos),
HLL_TODO_EXPORT(GetListBoxScrollPos, GUIEngine_GetListBoxScrollPos),
HLL_TODO_EXPORT(AddListBoxItem, GUIEngine_AddListBoxItem),
HLL_TODO_EXPORT(SetListBoxItem, GUIEngine_SetListBoxItem),
HLL_TODO_EXPORT(GetListBoxItemCount, GUIEngine_GetListBoxItemCount),
HLL_TODO_EXPORT(GetListBoxItem, GUIEngine_GetListBoxItem),
HLL_TODO_EXPORT(EraseListBoxItem, GUIEngine_EraseListBoxItem),
HLL_TODO_EXPORT(ClearListBoxItem, GUIEngine_ClearListBoxItem),
HLL_TODO_EXPORT(SetListBoxFontProperty, GUIEngine_SetListBoxFontProperty),
HLL_TODO_EXPORT(GetListBoxFontProperty, GUIEngine_GetListBoxFontProperty),
HLL_TODO_EXPORT(SetListBoxSelectIndex, GUIEngine_SetListBoxSelectIndex),
HLL_TODO_EXPORT(GetListBoxSelectIndex, GUIEngine_GetListBoxSelectIndex),
HLL_TODO_EXPORT(SetComboBoxPos, GUIEngine_SetComboBoxPos),
HLL_TODO_EXPORT(SetComboBoxZ, GUIEngine_SetComboBoxZ),
HLL_TODO_EXPORT(GetComboBoxX, GUIEngine_GetComboBoxX),
HLL_TODO_EXPORT(GetComboBoxY, GUIEngine_GetComboBoxY),
HLL_TODO_EXPORT(GetComboBoxZ, GUIEngine_GetComboBoxZ),
HLL_TODO_EXPORT(SetComboBoxWidth, GUIEngine_SetComboBoxWidth),
HLL_TODO_EXPORT(SetComboBoxHeight, GUIEngine_SetComboBoxHeight),
HLL_TODO_EXPORT(GetComboBoxWidth, GUIEngine_GetComboBoxWidth),
HLL_TODO_EXPORT(GetComboBoxHeight, GUIEngine_GetComboBoxHeight),
HLL_TODO_EXPORT(SetComboBoxTextWidthMargin, GUIEngine_SetComboBoxTextWidthMargin),
HLL_TODO_EXPORT(SetComboBoxTextHeightMargin, GUIEngine_SetComboBoxTextHeightMargin),
HLL_TODO_EXPORT(GetComboBoxTextWidthMargin, GUIEngine_GetComboBoxTextWidthMargin),
HLL_TODO_EXPORT(GetComboBoxTextHeightMargin, GUIEngine_GetComboBoxTextHeightMargin),
HLL_TODO_EXPORT(SetComboBoxShow, GUIEngine_SetComboBoxShow),
HLL_TODO_EXPORT(IsComboBoxShow, GUIEngine_IsComboBoxShow),
HLL_TODO_EXPORT(SetComboBoxCGName, GUIEngine_SetComboBoxCGName),
HLL_TODO_EXPORT(GetComboBoxCGName, GUIEngine_GetComboBoxCGName),
HLL_TODO_EXPORT(SetComboBoxText, GUIEngine_SetComboBoxText),
HLL_TODO_EXPORT(GetComboBoxText, GUIEngine_GetComboBoxText),
HLL_TODO_EXPORT(SetComboBoxFontProperty, GUIEngine_SetComboBoxFontProperty),
HLL_TODO_EXPORT(GetComboBoxFontProperty, GUIEngine_GetComboBoxFontProperty),
HLL_TODO_EXPORT(SetMultiTextBoxPos, GUIEngine_SetMultiTextBoxPos),
HLL_TODO_EXPORT(SetMultiTextBoxZ, GUIEngine_SetMultiTextBoxZ),
HLL_TODO_EXPORT(GetMultiTextBoxX, GUIEngine_GetMultiTextBoxX),
HLL_TODO_EXPORT(GetMultiTextBoxY, GUIEngine_GetMultiTextBoxY),
HLL_TODO_EXPORT(GetMultiTextBoxZ, GUIEngine_GetMultiTextBoxZ),
HLL_TODO_EXPORT(SetMultiTextBoxWidth, GUIEngine_SetMultiTextBoxWidth),
HLL_TODO_EXPORT(SetMultiTextBoxHeight, GUIEngine_SetMultiTextBoxHeight),
HLL_TODO_EXPORT(GetMultiTextBoxWidth, GUIEngine_GetMultiTextBoxWidth),
HLL_TODO_EXPORT(GetMultiTextBoxHeight, GUIEngine_GetMultiTextBoxHeight),
HLL_TODO_EXPORT(SetMultiTextBoxShow, GUIEngine_SetMultiTextBoxShow),
HLL_TODO_EXPORT(IsMultiTextBoxShow, GUIEngine_IsMultiTextBoxShow),
HLL_TODO_EXPORT(SetMultiTextBoxFontProperty, GUIEngine_SetMultiTextBoxFontProperty),
HLL_TODO_EXPORT(GetMultiTextBoxFontProperty, GUIEngine_GetMultiTextBoxFontProperty),
HLL_TODO_EXPORT(SetMultiTextBoxText, GUIEngine_SetMultiTextBoxText),
HLL_TODO_EXPORT(GetMultiTextBoxText, GUIEngine_GetMultiTextBoxText),
HLL_TODO_EXPORT(SetMultiTextBoxMaxTextLength, GUIEngine_SetMultiTextBoxMaxTextLength),
HLL_TODO_EXPORT(GetMultiTextBoxMaxTextLength, GUIEngine_GetMultiTextBoxMaxTextLength),
HLL_TODO_EXPORT(SetMultiTextBoxSelectR, GUIEngine_SetMultiTextBoxSelectR),
HLL_TODO_EXPORT(SetMultiTextBoxSelectG, GUIEngine_SetMultiTextBoxSelectG),
HLL_TODO_EXPORT(SetMultiTextBoxSelectB, GUIEngine_SetMultiTextBoxSelectB),
HLL_TODO_EXPORT(GetMultiTextBoxSelectR, GUIEngine_GetMultiTextBoxSelectR),
HLL_TODO_EXPORT(GetMultiTextBoxSelectG, GUIEngine_GetMultiTextBoxSelectG),
HLL_TODO_EXPORT(GetMultiTextBoxSelectB, GUIEngine_GetMultiTextBoxSelectB),
HLL_TODO_EXPORT(SetMultiTextBoxCGName, GUIEngine_SetMultiTextBoxCGName),
HLL_TODO_EXPORT(GetMultiTextBoxCGName, GUIEngine_GetMultiTextBoxCGName),
HLL_EXPORT(Parts_SetPartsCG, PE_SetPartsCG),
HLL_EXPORT(Parts_GetPartsCGName, PE_GetPartsCGName),
HLL_EXPORT(Parts_SetPartsCGSurfaceArea, PE_SetPartsCGSurfaceArea),
HLL_EXPORT(Parts_SetLoopCG, PE_SetLoopCG),
HLL_EXPORT(Parts_SetLoopCGSurfaceArea, PE_SetLoopCGSurfaceArea),
HLL_EXPORT(Parts_SetText, PE_SetText),
HLL_EXPORT(Parts_AddPartsText, PE_AddPartsText),
HLL_TODO_EXPORT(Parts_DeletePartsTopTextLine, GUIEngine_Parts_DeletePartsTopTextLine),
HLL_EXPORT(Parts_SetPartsTextSurfaceArea, PE_SetPartsTextSurfaceArea),
HLL_TODO_EXPORT(Parts_SetPartsTextHighlight, GUIEngine_Parts_SetPartsTextHighlight),
HLL_TODO_EXPORT(Parts_AddPartsTextHighlight, GUIEngine_Parts_AddPartsTextHighlight),
HLL_TODO_EXPORT(Parts_ClearPartsTextHighlight, GUIEngine_Parts_ClearPartsTextHighlight),
HLL_TODO_EXPORT(Parts_SetPartsTextCountReturn, GUIEngine_Parts_SetPartsTextCountReturn),
HLL_TODO_EXPORT(Parts_GetPartsTextCountReturn, GUIEngine_Parts_GetPartsTextCountReturn),
HLL_EXPORT(Parts_SetFont, PE_SetFont),
HLL_EXPORT(Parts_SetPartsFontType, PE_SetPartsFontType),
HLL_EXPORT(Parts_SetPartsFontSize, PE_SetPartsFontSize),
HLL_EXPORT(Parts_SetPartsFontColor, PE_SetPartsFontColor),
HLL_EXPORT(Parts_SetPartsFontBoldWeight, PE_SetPartsFontBoldWeight),
HLL_EXPORT(Parts_SetPartsFontEdgeColor, PE_SetPartsFontEdgeColor),
HLL_EXPORT(Parts_SetPartsFontEdgeWeight, PE_SetPartsFontEdgeWeight),
HLL_EXPORT(Parts_SetTextCharSpace, PE_SetTextCharSpace),
HLL_EXPORT(Parts_SetTextLineSpace, PE_SetTextLineSpace),
HLL_TODO_EXPORT(Parts_SetHGaugeCG, GUIEngine_Parts_SetHGaugeCG),
HLL_TODO_EXPORT(Parts_SetHGaugeRate, GUIEngine_Parts_SetHGaugeRate),
HLL_TODO_EXPORT(Parts_SetVGaugeCG, GUIEngine_Parts_SetVGaugeCG),
HLL_TODO_EXPORT(Parts_SetVGaugeRate, GUIEngine_Parts_SetVGaugeRate),
HLL_EXPORT(Parts_SetHGaugeSurfaceArea, PE_SetHGaugeSurfaceArea),
HLL_EXPORT(Parts_SetVGaugeSurfaceArea, PE_SetVGaugeSurfaceArea),
HLL_TODO_EXPORT(Parts_SetNumeralCG, GUIEngine_Parts_SetNumeralCG),
HLL_EXPORT(Parts_SetNumeralLinkedCGNumberWidthWidthList, PE_SetNumeralLinkedCGNumberWidthWidthList),
HLL_TODO_EXPORT(Parts_SetNumeralFont, GUIEngine_Parts_SetNumeralFont),
HLL_EXPORT(Parts_SetNumeralNumber, PE_SetNumeralNumber),
HLL_EXPORT(Parts_SetNumeralShowComma, PE_SetNumeralShowComma),
HLL_EXPORT(Parts_SetNumeralSpace, PE_SetNumeralSpace),
HLL_EXPORT(Parts_SetNumeralLength, PE_SetNumeralLength),
HLL_EXPORT(Parts_SetNumeralSurfaceArea, PE_SetNumeralSurfaceArea),
HLL_TODO_EXPORT(Parts_SetPartsRectangleDetectionSize, GUIEngine_Parts_SetPartsRectangleDetectionSize),
HLL_TODO_EXPORT(Parts_SetPartsRectangleDetectionSurfaceArea, GUIEngine_Parts_SetPartsRectangleDetectionSurfaceArea),
HLL_TODO_EXPORT(Parts_SetPartsCGDetectionSize, GUIEngine_Parts_SetPartsCGDetectionSize),
HLL_TODO_EXPORT(Parts_SetPartsCGDetectionSurfaceArea, GUIEngine_Parts_SetPartsCGDetectionSurfaceArea),
HLL_TODO_EXPORT(Parts_SetPartsFlat, GUIEngine_Parts_SetPartsFlat),
HLL_TODO_EXPORT(Parts_IsPartsFlatEnd, GUIEngine_Parts_IsPartsFlatEnd),
HLL_TODO_EXPORT(Parts_GetPartsFlatCurrentFrameNumber, GUIEngine_Parts_GetPartsFlatCurrentFrameNumber),
HLL_TODO_EXPORT(Parts_BackPartsFlatBeginFrame, GUIEngine_Parts_BackPartsFlatBeginFrame),
HLL_TODO_EXPORT(Parts_StepPartsFlatFinalFrame, GUIEngine_Parts_StepPartsFlatFinalFrame),
HLL_TODO_EXPORT(Parts_SetPartsFlatSurfaceArea, GUIEngine_Parts_SetPartsFlatSurfaceArea),
HLL_TODO_EXPORT(Parts_SetPartsFlatAndStop, GUIEngine_Parts_SetPartsFlatAndStop),
HLL_TODO_EXPORT(Parts_StopPartsFlat, GUIEngine_Parts_StopPartsFlat),
HLL_TODO_EXPORT(Parts_StartPartsFlat, GUIEngine_Parts_StartPartsFlat),
HLL_TODO_EXPORT(Parts_GoFramePartsFlat, GUIEngine_Parts_GoFramePartsFlat),
HLL_TODO_EXPORT(Parts_GetPartsFlatEndFrame, GUIEngine_Parts_GetPartsFlatEndFrame),
HLL_TODO_EXPORT(Parts_ExistsFlatFile, GUIEngine_Parts_ExistsFlatFile),
HLL_TODO_EXPORT(Parts_ClearPartsConstructionProcess, GUIEngine_Parts_ClearPartsConstructionProcess),
HLL_EXPORT(Parts_AddCreateToPartsConstructionProcess, PE_AddCreateToPartsConstructionProcess),
HLL_EXPORT(Parts_AddCreatePixelOnlyToPartsConstructionProcess, PE_AddCreatePixelOnlyToPartsConstructionProcess),
HLL_EXPORT(Parts_AddCreateCGToProcess, PE_AddCreateCGToProcess),
HLL_EXPORT(Parts_AddFillToPartsConstructionProcess, PE_AddFillToPartsConstructionProcess),
HLL_EXPORT(Parts_AddFillAlphaColorToPartsConstructionProcess, PE_AddFillAlphaColorToPartsConstructionProcess),
HLL_EXPORT(Parts_AddFillAMapToPartsConstructionProcess, PE_AddFillAMapToPartsConstructionProcess),
HLL_TODO_EXPORT(Parts_AddFillWithAlphaToPartsConstructionProcess, GUIEngine_Parts_AddFillWithAlphaToPartsConstructionProcess),
HLL_TODO_EXPORT(Parts_AddFillGradationHorizonToPartsConstructionProcess, GUIEngine_Parts_AddFillGradationHorizonToPartsConstructionProcess),
HLL_TODO_EXPORT(Parts_AddDrawRectToPartsConstructionProcess, GUIEngine_Parts_AddDrawRectToPartsConstructionProcess),
HLL_EXPORT(Parts_AddDrawCutCGToPartsConstructionProcess, PE_AddDrawCutCGToPartsConstructionProcess),
HLL_EXPORT(Parts_AddCopyCutCGToPartsConstructionProcess, PE_AddCopyCutCGToPartsConstructionProcess),
HLL_TODO_EXPORT(Parts_AddGrayFilterToPartsConstructionProcess, GUIEngine_Parts_AddGrayFilterToPartsConstructionProcess),
HLL_TODO_EXPORT(Parts_AddAddFilterToPartsConstructionProcess, GUIEngine_Parts_AddAddFilterToPartsConstructionProcess),
HLL_TODO_EXPORT(Parts_AddMulFilterToPartsConstructionProcess, GUIEngine_Parts_AddMulFilterToPartsConstructionProcess),
HLL_TODO_EXPORT(Parts_AddDrawLineToPartsConstructionProcess, GUIEngine_Parts_AddDrawLineToPartsConstructionProcess),
HLL_EXPORT(Parts_BuildPartsConstructionProcess, PE_BuildPartsConstructionProcess),
HLL_EXPORT(Parts_AddDrawTextToPartsConstructionProcess, PE_AddDrawTextToPartsConstructionProcess),
HLL_EXPORT(Parts_AddCopyTextToPartsConstructionProcess, PE_AddCopyTextToPartsConstructionProcess),
HLL_EXPORT(Parts_SetPartsConstructionSurfaceArea, PE_SetPartsConstructionSurfaceArea),
HLL_TODO_EXPORT(Parts_CreateParts3DLayerPluginID, GUIEngine_Parts_CreateParts3DLayerPluginID),
HLL_TODO_EXPORT(Parts_GetParts3DLayerPluginID, GUIEngine_Parts_GetParts3DLayerPluginID),
HLL_TODO_EXPORT(Parts_ReleaseParts3DLayerPluginID, GUIEngine_Parts_ReleaseParts3DLayerPluginID),
HLL_EXPORT(Parts_SetPos, PE_SetPos),
HLL_EXPORT(Parts_SetZ, PE_SetZ),
HLL_EXPORT(Parts_SetShow, PE_SetShow),
HLL_EXPORT(Parts_SetAlpha, PE_SetAlpha),
HLL_EXPORT(Parts_SetPartsDrawFilter, PE_SetPartsDrawFilter),
HLL_TODO_EXPORT(Parts_SetPassCursor, GUIEngine_Parts_SetPassCursor),
HLL_TODO_EXPORT(Parts_SetClickable, GUIEngine_Parts_SetClickable),
HLL_TODO_EXPORT(Parts_SetSpeedupRateByMessageSkip, GUIEngine_Parts_SetSpeedupRateByMessageSkip),
HLL_TODO_EXPORT(Parts_SetResetTimerByChangeInputStatus, GUIEngine_Parts_SetResetTimerByChangeInputStatus),
HLL_EXPORT(Parts_SetAddColor, PE_SetAddColor),
HLL_EXPORT(Parts_SetMultiplyColor, PE_SetMultiplyColor),
HLL_TODO_EXPORT(Parts_SetDrag, GUIEngine_Parts_SetDrag),
HLL_EXPORT(Parts_SetPartsOriginPosMode, PE_SetPartsOriginPosMode),
HLL_EXPORT(Parts_SetParentPartsNumber, PE_SetParentPartsNumber),
HLL_TODO_EXPORT(Parts_SetInputState, GUIEngine_Parts_SetInputState),
HLL_TODO_EXPORT(Parts_SetOnCursorShowLinkPartsNumber, GUIEngine_Parts_SetOnCursorShowLinkPartsNumber),
HLL_EXPORT(Parts_SetPartsMessageWindowShowLink, PE_SetPartsMessageWindowShowLink),
HLL_TODO_EXPORT(Parts_SetSoundNumber, GUIEngine_Parts_SetSoundNumber),
HLL_TODO_EXPORT(Parts_SetClickMissSoundNumber, GUIEngine_Parts_SetClickMissSoundNumber),
HLL_EXPORT(Parts_SetPartsMagX, PE_SetPartsMagX),
HLL_EXPORT(Parts_SetPartsMagY, PE_SetPartsMagY),
HLL_EXPORT(Parts_SetPartsRotateX, PE_SetPartsRotateX),
HLL_EXPORT(Parts_SetPartsRotateY, PE_SetPartsRotateY),
HLL_EXPORT(Parts_SetPartsRotateZ, PE_SetPartsRotateZ),
HLL_TODO_EXPORT(Parts_SetPartsAlphaClipperPartsNumber, GUIEngine_Parts_SetPartsAlphaClipperPartsNumber),
HLL_EXPORT(Parts_SetPartsPixelDecide, PE_SetPartsPixelDecide),
HLL_EXPORT(Parts_GetPartsX, PE_GetPartsX),
HLL_EXPORT(Parts_GetPartsY, PE_GetPartsY),
HLL_EXPORT(Parts_GetPartsZ, PE_GetPartsZ),
HLL_EXPORT(Parts_GetPartsShow, PE_GetPartsShow),
HLL_EXPORT(Parts_GetPartsAlpha, PE_GetPartsAlpha),
HLL_TODO_EXPORT(Parts_GetPartsDrawFilter, GUIEngine_Parts_GetPartsDrawFilter),
HLL_TODO_EXPORT(Parts_GetPartsPassCursor, GUIEngine_Parts_GetPartsPassCursor),
HLL_TODO_EXPORT(Parts_GetPartsClickable, GUIEngine_Parts_GetPartsClickable),
HLL_TODO_EXPORT(Parts_GetPartsSpeedupRateByMessageSkip, GUIEngine_Parts_GetPartsSpeedupRateByMessageSkip),
HLL_TODO_EXPORT(Parts_GetResetTimerByChangeInputStatus, GUIEngine_Parts_GetResetTimerByChangeInputStatus),
HLL_TODO_EXPORT(Parts_GetAddColor, GUIEngine_Parts_GetAddColor),
HLL_TODO_EXPORT(Parts_GetMultiplyColor, GUIEngine_Parts_GetMultiplyColor),
HLL_TODO_EXPORT(Parts_GetPartsDrag, GUIEngine_Parts_GetPartsDrag),
HLL_TODO_EXPORT(Parts_GetPartsOriginPosMode, GUIEngine_Parts_GetPartsOriginPosMode),
HLL_TODO_EXPORT(Parts_GetParentPartsNumber, GUIEngine_Parts_GetParentPartsNumber),
HLL_TODO_EXPORT(Parts_GetInputState, GUIEngine_Parts_GetInputState),
HLL_TODO_EXPORT(Parts_GetOnCursorShowLinkPartsNumber, GUIEngine_Parts_GetOnCursorShowLinkPartsNumber),
HLL_TODO_EXPORT(Parts_GetPartsMessageWindowShowLink, GUIEngine_Parts_GetPartsMessageWindowShowLink),
HLL_TODO_EXPORT(Parts_GetSoundNumber, GUIEngine_Parts_GetSoundNumber),
HLL_TODO_EXPORT(Parts_GetClickMissSoundNumber, GUIEngine_Parts_GetClickMissSoundNumber),
HLL_TODO_EXPORT(Parts_GetPartsMagX, GUIEngine_Parts_GetPartsMagX),
HLL_TODO_EXPORT(Parts_GetPartsMagY, GUIEngine_Parts_GetPartsMagY),
HLL_TODO_EXPORT(Parts_GetPartsRotateX, GUIEngine_Parts_GetPartsRotateX),
HLL_TODO_EXPORT(Parts_GetPartsRotateY, GUIEngine_Parts_GetPartsRotateY),
HLL_TODO_EXPORT(Parts_GetPartsRotateZ, GUIEngine_Parts_GetPartsRotateZ),
HLL_TODO_EXPORT(Parts_GetPartsAlphaClipperPartsNumber, GUIEngine_Parts_GetPartsAlphaClipperPartsNumber),
HLL_TODO_EXPORT(Parts_IsPartsPixelDecide, GUIEngine_Parts_IsPartsPixelDecide),
HLL_EXPORT(Parts_GetPartsUpperLeftPosX, PE_GetPartsUpperLeftPosX),
HLL_EXPORT(Parts_GetPartsUpperLeftPosY, PE_GetPartsUpperLeftPosY),
HLL_EXPORT(Parts_GetPartsWidth, PE_GetPartsWidth),
HLL_EXPORT(Parts_GetPartsHeight, PE_GetPartsHeight),
HLL_EXPORT(Parts_AddMotionPos, PE_AddMotionPos_curve),
HLL_EXPORT(Parts_AddMotionAlpha, PE_AddMotionAlpha_curve),
HLL_TODO_EXPORT(Parts_AddMotionCG, GUIEngine_Parts_AddMotionCG),
HLL_TODO_EXPORT(Parts_AddMotionCGTermination, GUIEngine_Parts_AddMotionCGTermination),
HLL_TODO_EXPORT(Parts_AddMotionHGaugeRate, GUIEngine_Parts_AddMotionHGaugeRate),
HLL_TODO_EXPORT(Parts_AddMotionVGaugeRate, GUIEngine_Parts_AddMotionVGaugeRate),
HLL_TODO_EXPORT(Parts_AddMotionNumeralNumber, GUIEngine_Parts_AddMotionNumeralNumber),
HLL_TODO_EXPORT(Parts_AddMotionMagX, GUIEngine_Parts_AddMotionMagX),
HLL_TODO_EXPORT(Parts_AddMotionMagY, GUIEngine_Parts_AddMotionMagY),
HLL_TODO_EXPORT(Parts_AddMotionRotateX, GUIEngine_Parts_AddMotionRotateX),
HLL_TODO_EXPORT(Parts_AddMotionRotateY, GUIEngine_Parts_AddMotionRotateY),
HLL_TODO_EXPORT(Parts_AddMotionRotateZ, GUIEngine_Parts_AddMotionRotateZ),
HLL_EXPORT(Parts_AddMotionVibrationSize, PE_AddMotionVibrationSize),
HLL_TODO_EXPORT(Parts_AddWholeMotionVibrationSize, GUIEngine_Parts_AddWholeMotionVibrationSize),
HLL_TODO_EXPORT(Parts_AddMotionSound, GUIEngine_Parts_AddMotionSound),
HLL_EXPORT(Parts_IsCursorIn, PE_IsCursorIn),
HLL_TODO_EXPORT(Parts_SetThumbnailReductionSize, GUIEngine_Parts_SetThumbnailReductionSize),
HLL_TODO_EXPORT(Parts_SetThumbnailMode, GUIEngine_Parts_SetThumbnailMode),
HLL_TODO_EXPORT(GetClickNumber, GUIEngine_GetClickNumber),
HLL_EXPORT(Parts_BeginMotion, PE_BeginMotion),
HLL_EXPORT(Parts_EndMotion, PE_EndMotion),
HLL_EXPORT(Parts_IsMotion, PE_IsMotion),
HLL_TODO_EXPORT(Parts_SeekEndMotion, GUIEngine_Parts_SeekEndMotion),
HLL_EXPORT(Parts_UpdateMotionTime, PE_UpdateMotionTime),
HLL_EXPORT(Save, PE_Save),
HLL_EXPORT(SaveWithoutHideParts, PE_SaveWithoutHideParts),
HLL_TODO_EXPORT(Load, GUIEngine_Load));
+168 -1921
View File
File diff suppressed because it is too large Load Diff
+36 -19
View File
@@ -26,6 +26,7 @@
#include "audio.h"
#include "effect.h"
#include "gfx/gfx.h"
#include "gfx/font.h"
#include "input.h"
#include "vm.h"
#include "xsystem4.h"
@@ -353,6 +354,8 @@ static void Gpx2Plus_CopyStretchReduce(int destSurface, int dx, int dy, int dWid
static void Gpx2Plus_CopyStretchReduceAMap(int destSurface, int dx, int dy, int dWidth, int dHeight, int srcSurface, int sx, int sy, int sWidth, int sHeight)
{
if (game_daibanchou_en)
sWidth /= 2;
struct texture *dst = get_texture(destSurface);
struct texture *src = get_texture(srcSurface);
if (!dst || !src)
@@ -420,7 +423,7 @@ static void Gpx2Plus_SetFontName(struct string *name)
else if (!strcmp(u, "MS 明朝"))
gfx_set_font_face(FONT_MINCHO);
else
WARNING("Unknown font name '%s'", u);
WARNING("Unknown font name '%s'", display_utf0(u));
free(u);
}
@@ -485,15 +488,29 @@ static void Gpx2Plus_MsgDraw(int surface, int x, int y)
if (!dst)
return;
struct text_metrics tm = { .size = 16, .weight = FW_NORMAL };
int char_space = 0;
struct text_style ts = {
.face = FONT_GOTHIC,
.size = 16.0f,
.bold_width = 0.0f,
.weight = FW_NORMAL,
.edge_left = 0.0f,
.edge_up = 0.0f,
.edge_right = 0.0f,
.edge_down = 0.0f,
.color = {0,0,0,0},
.edge_color = {0,0,0,0},
.scale_x = 1.0,
.space_scale_x = 1.0f,
.font_spacing = 0.0f,
.font_size = NULL
};
int line_space = 0;
int old_size = 16;
enum font_face old_face = FONT_GOTHIC;
Point pos = POINT(x, y);
char *s = msgbuf.text;
int line_height = calculate_line_height(tm.size, s);
int line_height = calculate_line_height(ts.size, s);
while (*s) {
int skiplen = 0, a1, a2, a3;
if (*s != '<') {
@@ -504,40 +521,40 @@ static void Gpx2Plus_MsgDraw(int surface, int x, int y)
} else {
skiplen = strlen(s);
}
pos.y += line_height - tm.size; // bottom align
pos.x += gfx_render_text(dst, pos, s, &tm, char_space);
pos.y -= line_height - tm.size;
pos.y += line_height - ts.size; // bottom align
pos.x += gfx_render_text(dst, pos.x, pos.y, s, &ts);
pos.y -= line_height - ts.size;
if (lb)
*lb = '<';
} else if (sscanf(s, "<F%d>%n", &a1, &skiplen) == 1) {
old_face = tm.face;
tm.face = a1;
old_face = ts.face;
ts.face = a1;
} else if (!strncmp(s, "</F>", 4)) {
skiplen = 4;
tm.face = old_face;
ts.face = old_face;
} else if (sscanf(s, "<S%d>%n", &a1, &skiplen) == 1) {
old_size = tm.size;
tm.size = a1;
old_size = ts.size;
ts.size = a1;
} else if (!strncmp(s, "</S>", 4)) {
skiplen = 4;
tm.size = old_size;
ts.size = old_size;
} else if (sscanf(s, "<C%d,%d,%d>%n", &a1, &a2, &a3, &skiplen) == 3) {
tm.color = (SDL_Color) { .r = a1, .g = a2, .b = a3, .a = 255 };
ts.color = (SDL_Color) { .r = a1, .g = a2, .b = a3, .a = 255 };
} else if (sscanf(s, "<KC%d,%d,%d>%n", &a1, &a2, &a3, &skiplen) == 3) {
tm.outline_color = (SDL_Color) { .r = a1, .g = a2, .b = a3, .a = 255 };
ts.edge_color = (SDL_Color) { .r = a1, .g = a2, .b = a3, .a = 255 };
} else if (!strncmp(s, "<K>", 3)) {
skiplen = 3;
tm.outline_right = tm.outline_down = 2;
ts.edge_right = ts.edge_down = 2;
} else if (!strncmp(s, "</K>", 4)) {
skiplen = 4;
tm.outline_right = tm.outline_down = 0;
ts.edge_right = ts.edge_down = 0;
} else if (!strncmp(s, "<R>", 3)) {
skiplen = 3;
pos.x = x;
pos.y += line_height + line_space;
line_height = calculate_line_height(tm.size, s + skiplen);
line_height = calculate_line_height(ts.size, s + skiplen);
} else if (sscanf(s, "<SPW%d>%n", &a1, &skiplen) == 1) {
char_space = a1;
ts.font_spacing = a1;
} else if (sscanf(s, "<SPH%d>%n", &a1, &skiplen) == 1) {
line_space = a1;
} else {

Some files were not shown because too many files have changed in this diff Show More