simple 3D

This commit is contained in:
CatWindow 2026-08-16 16:14:35 +03:00
parent 0a45a117e3
commit 529650b84c
8 changed files with 297 additions and 63 deletions

View file

@ -64,15 +64,19 @@ DEF_PROP_I(Sprite, WaveAmp)
DEF_PROP_I(Sprite, WaveLength)
DEF_PROP_I(Sprite, WaveSpeed)
DEF_PROP_I(Sprite, Shader)
DEF_PROP_I(Sprite, PerspectiveZ)
DEF_PROP_F(Sprite, ZoomX)
DEF_PROP_F(Sprite, ZoomY)
DEF_PROP_F(Sprite, Angle)
DEF_PROP_F(Sprite, WavePhase)
DEF_PROP_F(Sprite, PerspectiveRotationX)
DEF_PROP_F(Sprite, PerspectiveRotationY)
DEF_PROP_B(Sprite, MirrorX)
DEF_PROP_B(Sprite, MirrorY)
DEF_PROP_B(Sprite, Obscured)
DEF_PROP_B(Sprite, PerspectiveMode)
RB_METHOD(spriteWidth){
RB_UNUSED_PARAM;
@ -125,6 +129,10 @@ void spriteBindingInit(){
INIT_PROP_BIND( Sprite, Modulate, "modulate" );
INIT_PROP_BIND( Sprite, Obscured, "obscured" );
INIT_PROP_BIND( Sprite, Shader, "shader" );
INIT_PROP_BIND( Sprite, PerspectiveMode, "pm");
INIT_PROP_BIND( Sprite, PerspectiveZ, "pz");
INIT_PROP_BIND( Sprite, PerspectiveRotationX, "rx");
INIT_PROP_BIND( Sprite, PerspectiveRotationY, "ry");
_rb_define_method(klass, "width", spriteWidth);
_rb_define_method(klass, "height", spriteHeight);

View file

@ -90,9 +90,10 @@ class Scene_OF
@miss_sound = Audio.create_sound("Audio/SE/shatter")
@viewport_bg = Viewport.new(0, 0, Graphics.width, Graphics.height)
@viewport_ui = Viewport.new(0, 0, Graphics.width, Graphics.height)
@viewport_ui.ox = -Graphics.width / 2
@viewport_ui.oy = -Graphics.height / 2
@viewport_ui.ox = @viewport_bg.ox = -Graphics.width / 2
@viewport_ui.oy = @viewport_bg.oy = -Graphics.height / 2
@spritesheet = RPG::Cache.misc(".cats")
@cat_flying_arrows = []
@ -165,6 +166,20 @@ class Scene_OF
@bst_debug = Sprite.new(@viewport_ui)
@bst_debug.bitmap = Bitmap.new(300, 40)
@test_bitmap = Bitmap.new(64, 64)
@test_bitmap.stretch_blt(Rect.new(0, 0, 64, 64), @spritesheet, SPRITES[:player_target_arrow_down])
@threeD_test1 = Sprite.new(@viewport_bg)
@threeD_test2 = Sprite.new(@viewport_bg)
@threeD_test1.bitmap = @test_bitmap
@threeD_test2.bitmap = @simple_bitmap
@threeD_test1.x = -300
@threeD_test1.ry = 90
@threeD_test1.pm = @threeD_test2.pm = true
@threeD_test1.zoom_x = @threeD_test1.zoom_y = 2
@threeD_test2.zoom_x = @threeD_test2.zoom_y = 128
@threeD_test1.ox = @threeD_test1.oy = 32
@threeD_test2.ox = @threeD_test2.oy = 0.5
@total_time = 0
@bump_timeout = 999999
@bump_time = 999999
@ -218,6 +233,9 @@ class Scene_OF
@bst_debug.bitmap.clear
@bst_debug.bitmap.draw_text(Rect.new(0, 0, 300, 40), "#{beat} : #{step} : #{tick}")
@threeD_test1.pz = Math.sin(@total_time / 180.0 * Math::PI) * 400 + 400
@threeD_test2.rx += 4
@bump_timeout -= 1
@icons_bump_timeout -= 1
if @bump_timeout <= 0

View file

@ -26,6 +26,8 @@
#include <SDL3/SDL_rect.h>
constexpr float PI = 3.14159265358979323846f;
struct Vec2{
float x, y;

View file

@ -237,6 +237,34 @@ void ShaderBase::applyViewportProj(){
projMat.set(Vec2i(vp.w, vp.h));
}
void ShaderBase::applyPerspectiveProj()
{
const IntRect &vp = glState.viewport.get();
const float width = (float)vp.w;
const float height = (float)vp.h;
const float cameraDistance = 1000.0f;
const float nearPlane = 1.0f;
const float farPlane = 10000.0f;
const float sx = 2.0f * cameraDistance / width;
const float sy = 2.0f * cameraDistance / height;
const float A = -(farPlane + nearPlane) / (farPlane - nearPlane);
const float B = -(2.0f * farPlane * nearPlane) / (farPlane - nearPlane);
GLfloat mat[16] = {
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, A, -1,
-cameraDistance, -cameraDistance, B, cameraDistance
};
gl.UniformMatrix4fv(projMat.u_mat, 1, GL_FALSE, mat);
}
void ShaderBase::setTexSize(const Vec2i &value){
gl.Uniform2f(u_texSizeInv, 1.f / value.x, 1.f / value.y);
}

View file

@ -69,6 +69,7 @@ public:
* calculates the corresponding ortho projection matrix
* and loads it into the shaders uniform */
void applyViewportProj();
void applyPerspectiveProj();
void setTexSize(const Vec2i &value);
void setTranslation(const Vec2i &value);

View file

@ -318,6 +318,11 @@ DEF_ATTR_RD_SIMPLE(Sprite, WaveAmp, int, p->wave.amp)
DEF_ATTR_RD_SIMPLE(Sprite, WaveLength, int, p->wave.length)
DEF_ATTR_RD_SIMPLE(Sprite, WaveSpeed, int, p->wave.speed)
DEF_ATTR_RD_SIMPLE(Sprite, WavePhase, float, p->wave.phase)
// 3D shit
DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveMode, bool, p->trans.getPerspectiveMode())
DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveZ, int, p->trans.getPerspectiveZ())
DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveRotationX, float, p->trans.getPerspectiveRotation().x)
DEF_ATTR_RD_SIMPLE(Sprite, PerspectiveRotationY, float, p->trans.getPerspectiveRotation().y)
DEF_ATTR_SIMPLE(Sprite, BushOpacity, int, p->bushOpacity)
DEF_ATTR_SIMPLE(Sprite, Opacity, int, p->opacity)
@ -462,6 +467,42 @@ void Sprite::setBlendType(int type){
}
}
void Sprite::setPerspectiveMode(bool value){
guardDisposed();
if (p->trans.getPerspectiveMode() == value)
return;
p->trans.setPerspectiveMode(value);
}
void Sprite::setPerspectiveZ(int value){
guardDisposed();
if (p->trans.getPerspectiveZ() == value)
return;
p->trans.setPerspectiveZ(value);
}
void Sprite::setPerspectiveRotationX(float value){
guardDisposed();
if (p->trans.getPerspectiveRotation().x == value)
return;
p->trans.setPerspectiveRotation(Vec2(value, p->trans.getPerspectiveRotation().y));
}
void Sprite::setPerspectiveRotationY(float value){
guardDisposed();
if (p->trans.getPerspectiveRotation().y == value)
return;
p->trans.setPerspectiveRotation(Vec2(p->trans.getPerspectiveRotation().x, value));
}
#define DEF_WAVE_SETTER(Name, name, type) \
void Sprite::setWave##Name(type value) \
{ \
@ -517,7 +558,6 @@ void Sprite::draw(){
if (p->obscured || p->shader == ShaderType::SHADER_obscured){
ObscuredShader &shader = shState->shaders().obscured;
shader.bind();
shader.applyViewportProj();
shader.setObscured(shState->graphics().obscuredTex());
base = &shader;
}
@ -529,7 +569,6 @@ void Sprite::draw(){
PlaneShader &shader = shState->shaders().plane;
shader.bind();
shader.applyViewportProj();
shader.setTone(p->tone->norm);
shader.setColor(p->color->norm);
shader.setFlash(Vec4());
@ -586,7 +625,6 @@ void Sprite::draw(){
shader.setSpriteMat(p->trans.getMatrix());
shader.setAlpha(p->opacity.norm);
shader.applyViewportProj();
base = &shader;
}
else{
@ -594,7 +632,6 @@ void Sprite::draw(){
shader.bind();
shader.setSpriteMat(p->trans.getMatrix());
shader.applyViewportProj();
base = &shader;
}
@ -606,6 +643,10 @@ void Sprite::draw(){
boost::chrono::duration<float> elapsed = currentTime - startTime;
base->setTime(elapsed.count());
base->applyViewportProj();
if(p->trans.getPerspectiveMode())
base->applyPerspectiveProj();
glState.blendMode.pushSet(p->blendType);
p->bitmap->bindTex(*base);
@ -644,7 +685,6 @@ void Sprite::releaseResources(){
void Sprite::defaultSpriteShaderInit(SpriteShaderBase &shader){
shader.bind();
shader.applyViewportProj();
shader.setSpriteMat(p->trans.getMatrix());
shader.setTone(p->tone->norm);

View file

@ -72,6 +72,11 @@ public:
DECL_ATTR( WavePhase, float )
DECL_ATTR( Obscured, bool )
DECL_ATTR( Shader, int )
// 3D test shit
DECL_ATTR( PerspectiveMode, bool )
DECL_ATTR( PerspectiveZ, int )
DECL_ATTR( PerspectiveRotationX, float )
DECL_ATTR( PerspectiveRotationY, float )
void initDynAttribs();

View file

@ -52,13 +52,13 @@
#include <SDL3/SDL_stdinc.h>
constexpr float PI = 3.14159265358979323846f;
class Transform{
public:
Transform()
: scale(1, 1),
rotation(0),
perspectiveZ(0),
perspectiveRotation(0, 0),
dirty(true)
{
SDL_memset(matrix, 0, sizeof(matrix));
@ -67,12 +67,15 @@ public:
matrix[15] = 1;
}
Vec2 &getPosition() { return position; }
Vec2 &getOrigin() { return origin; }
Vec2 &getScale() { return scale; }
Vec2 &getGlobalScale() { return globalScale; }
float getRotation() { return rotation; }
float getGlobalRotation() { return globalRotation; }
Vec2 &getPosition() { return position; }
Vec2 &getOrigin() { return origin; }
Vec2 &getScale() { return scale; }
Vec2 &getGlobalScale() { return globalScale; }
Vec2 &getPerspectiveRotation() { return perspectiveRotation; }
float getRotation() { return rotation; }
float getGlobalRotation() { return globalRotation; }
float getPerspectiveZ() { return perspectiveZ; }
bool getPerspectiveMode() { return perspectiveMode; }
Vec2i getPositionI() const{
return Vec2i(position.x, position.y);
@ -82,11 +85,21 @@ public:
return Vec2i(origin.x, origin.y);
}
void setPerspectiveMode(bool mode) {
perspectiveMode = mode;
dirty = true;
}
void setPosition(const Vec2 &value){
position = value;
dirty = true;
}
void setPerspectiveZ(float value) {
perspectiveZ = value;
dirty = true;
}
void setOrigin(const Vec2 &value){
origin = value;
dirty = true;
@ -102,6 +115,11 @@ public:
dirty = true;
}
void setPerspectiveRotation(const Vec2 &value){
perspectiveRotation = value;
dirty = true;
}
void setGlobalRotation(float value){
globalRotation = value;
dirty = true;
@ -133,53 +151,161 @@ private:
if (globalRotation >= 360 || globalRotation < -360)
globalRotation = (float)SDL_fmod(globalRotation, 360);
if (!perspectiveMode) {
// object rotation cos and sin
float angle = rotation * PI / 180.0f;
float cosine = SDL_cos(angle);
float sine = SDL_sin(angle);
// object rotation cos and sin
float angle = rotation * PI / 180.0f;
float cosine = SDL_cos(angle);
float sine = SDL_sin(angle);
float sxc = scale.x * cosine;
float syc = scale.y * cosine;
float sxs = scale.x * sine;
float sys = scale.y * sine;
float sxc = scale.x * cosine;
float syc = scale.y * cosine;
float sxs = scale.x * sine;
float sys = scale.y * sine;
// object matrix
float a = sxc * globalScale.x;
float b = -sxs * globalScale.y;
float c = sys * globalScale.x;
float d = syc * globalScale.y;
// object matrix
float a = sxc * globalScale.x;
float b = -sxs * globalScale.y;
float c = sys * globalScale.x;
float d = syc * globalScale.y;
float tx = (-origin.x * sxc - origin.y * sys + position.x)
* globalScale.x;
float tx = (-origin.x * sxc - origin.y * sys + position.x)
* globalScale.x;
float ty = ( origin.x * sxs - origin.y * syc + position.y)
* globalScale.y;
float ty = ( origin.x * sxs - origin.y * syc + position.y)
* globalScale.y;
// viewport rotation cos and sin
float globalAngle = globalRotation * PI / 180.0f;
float gc = SDL_cos(globalAngle);
float gs = SDL_sin(globalAngle);
// viewport rotation cos and sin
float globalAngle = globalRotation * PI / 180.0f;
float gc = SDL_cos(globalAngle);
float gs = SDL_sin(globalAngle);
// basis rotation
float na = a * gc - b * gs;
float nb = a * gs + b * gc;
float nc = c * gc - d * gs;
float nd = c * gs + d * gc;
// basis rotation
float na = a * gc - b * gs;
float nb = a * gs + b * gc;
float nc = c * gc - d * gs;
float nd = c * gs + d * gc;
float dx = tx;
float dy = ty;
float dx = tx;
float dy = ty;
// appling global rotation
tx = dx * gc - dy * gs + offset.x;
ty = dx * gs + dy * gc + offset.y;
// appling global rotation
tx = dx * gc - dy * gs + offset.x;
ty = dx * gs + dy * gc + offset.y;
matrix[0] = na;
matrix[1] = nb;
matrix[4] = nc;
matrix[5] = nd;
matrix[12] = tx;
matrix[13] = ty;
matrix[0] = na;
matrix[1] = nb;
matrix[2] = 0;
matrix[3] = 0;
matrix[4] = nc;
matrix[5] = nd;
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = 1;
matrix[11] = 0;
matrix[12] = tx;
matrix[13] = ty;
matrix[14] = -1;
matrix[15] = 1;
}
else {
if (perspectiveRotation.x >= 360 || perspectiveRotation.x < -360)
perspectiveRotation.x = (float)SDL_fmod(perspectiveRotation.x, 360);
if (perspectiveRotation.y >= 360 || perspectiveRotation.y < -360)
perspectiveRotation.y = (float)SDL_fmod(perspectiveRotation.y, 360);
float rx = perspectiveRotation.x * PI / 180.0f;
float ry = perspectiveRotation.y * PI / 180.0f;
float rz = rotation * PI / 180.0f;
float cx = SDL_cos(rx);
float sx = SDL_sin(rx);
float cy = SDL_cos(ry);
float sy = SDL_sin(ry);
float cz = SDL_cos(rz);
float sz = SDL_sin(rz);
float m00 = cy * cz;
float m01 = cz * sx * sy - cx * sz;
float m02 = sx * sz + cx * cz * sy;
float m10 = cy * sz;
float m11 = cx * cz + sx * sy * sz;
float m12 = cx * sy * sz - cz * sx;
float m20 = -sy;
float m21 = cy * sx;
float m22 = cx * cy;
m00 *= scale.x;
m10 *= scale.x;
m20 *= scale.x;
m01 *= scale.y;
m11 *= scale.y;
m21 *= scale.y;
float globalAngle = globalRotation * PI / 180.0f;
float gc = SDL_cos(globalAngle);
float gs = SDL_sin(globalAngle);
// Rotate X/Y basis around Z
float r00 = m00 * gc - m01 * gs;
float r01 = m00 * gs + m01 * gc;
float r10 = m10 * gc - m11 * gs;
float r11 = m10 * gs + m11 * gc;
float r20 = m20 * gc - m21 * gs;
float r21 = m20 * gs + m21 * gc;
m00 = r00;
m01 = r01;
m10 = r10;
m11 = r11;
m20 = r20;
m21 = r21;
m00 *= globalScale.x;
m10 *= globalScale.x;
m20 *= globalScale.x;
m01 *= globalScale.y;
m11 *= globalScale.y;
m21 *= globalScale.y;
float tx = position.x - (m00 * origin.x + m01 * origin.y) + offset.x;
float ty = position.y - (m10 * origin.x + m11 * origin.y) + offset.y;
float tz = -perspectiveZ - (m20 * origin.x + m21 * origin.y);
matrix[0] = m00;
matrix[1] = m10;
matrix[2] = m20;
matrix[3] = 0;
matrix[4] = m01;
matrix[5] = m11;
matrix[6] = m21;
matrix[7] = 0;
matrix[8] = m02;
matrix[9] = m12;
matrix[10] = m22;
matrix[11] = 0;
matrix[12] = tx;
matrix[13] = ty;
matrix[14] = tz;
matrix[15] = 1;
}
}
Vec2 position;
@ -188,6 +314,12 @@ private:
float rotation;
float globalRotation;
// 3D moments lol
float perspectiveZ;
// X and Y, Z is just rotation
Vec2 perspectiveRotation;
bool perspectiveMode = false;
/* Silently added to position */
Vec2i offset;
/* Silently added to scale */