Compare commits

...

29 Commits

Author SHA1 Message Date
Andy_kl 410f936b7b Add posibility to write PEP 224 like documented variables. 2024-09-07 23:36:08 +04:00
Ren'Py Bot 79bda8a568 Merge branch 'fix' 2024-09-06 04:30:30 -04:00
Tom Rothamel 1fefbeba52 Remove checks for config.gl2. 2024-09-06 00:40:09 -04:00
Tom Rothamel 1336b5cfb8 Remove the gl, gles, and angle renderers. 2024-09-06 00:34:14 -04:00
Tom Rothamel 935a25490a Merge pull request #5766 from the66F95/render.pyx-debug
Update render.pyx
2024-09-05 13:18:04 -04:00
the66F95 5f73d6f1b2 Update render.pyx
still debug output present.
2024-09-05 19:09:43 +02:00
Ren'Py Bot 595e4d45bd Merge branch 'fix' 2024-09-05 04:30:30 -04:00
Ren'Py Bot c42667b197 Merge branch 'fix' 2024-09-04 04:30:30 -04:00
Ren'Py Bot 00750cb5d5 Merge branch 'fix' 2024-09-03 04:30:30 -04:00
Ren'Py Bot 5f42c6bff9 Merge branch 'fix' 2024-09-02 04:30:30 -04:00
Ren'Py Bot e6e11dab9f Merge branch 'fix' 2024-09-01 04:30:30 -04:00
Tom Rothamel 6351d60213 Merge pull request #5757 from sunrisesarsaparilla/indent-project.json
make project.json easier for humans to read
2024-08-31 23:55:26 -04:00
Sunrise Sarsaparilla 2928e5495c make project.json easier for humans to read 2024-08-31 20:32:52 -07:00
Ren'Py Bot ffd5eddaf9 Merge branch 'fix' 2024-08-31 04:30:30 -04:00
Ren'Py Bot 27b4c46013 Merge branch 'fix' 2024-08-30 04:30:30 -04:00
Ren'Py Bot c8da44781d Merge branch 'fix' 2024-08-29 04:30:30 -04:00
Ren'Py Bot a40d302500 Merge branch 'fix' 2024-08-28 04:30:30 -04:00
Mark 8ad44080ae doc: Fix example in dialogue.rst (#5736) 2024-08-27 16:52:01 -04:00
veydzh3r c41b740ae6 Update ukrainian (#5741)
* Update common.rpy

* Update developer.rpy

* Update gui.rpy

* Update launcher.rpy

* Update options.rpy

* Update screens.rpy

* Update script.rpym
2024-08-27 16:51:34 -04:00
Ren'Py Bot 67e508c979 Merge branch 'fix' 2024-08-27 04:30:30 -04:00
Ren'Py Bot a7e9d39c1d Merge branch 'fix' 2024-08-26 04:30:30 -04:00
Kassy 921ddb07f7 [Web] Only call syncfs once from MultiLocation functions (#5733)
* Do not call syncfs() twice in save_persistent()

With Ren'Py default config, MultiLocation.save_persistent() will call
save_persistent() on 2 different instances of FileLocation. They both
call synfc(), so the warning message "2 FS.syncfs operations in flight
at once, probably just doing extra work" shows up. This commit prevents
that.

* Create and use a context for syncfs pause

* Only call syncfs once from MultiLocation functions

This should handle all the functions of MultiLocation that call
functions of FileLocation that call syncfs().
2024-08-25 23:06:10 -04:00
Ren'Py Bot b2b222f23e Merge branch 'fix' 2024-08-25 04:30:30 -04:00
Ren'Py Bot af202584db Merge branch 'fix' 2024-08-24 22:23:52 -04:00
Ren'Py Bot d38dbc79b2 Merge branch 'fix' 2024-08-24 04:30:30 -04:00
Andrej Klychin 15c6fdf8c1 Merge pull request #5726 from AbdulGoodLooks/patch-4
Fix typos in changelog.rst
2024-08-24 00:21:10 +02:00
Abdul 5e02e88ec0 Fix typos in changelog.rst 2024-08-23 15:52:51 +01:00
Tom Rothamel 3337049968 py2: Disable build process. 2024-08-23 00:56:10 -04:00
Tom Rothamel 2565157a5a Bump versions. 2024-08-23 00:56:10 -04:00
21 changed files with 302 additions and 4267 deletions
+1 -1
View File
@@ -116,7 +116,7 @@ init python in project:
try:
with open(os.path.join(self.path, "project.json"), "w") as f:
json.dump(self.data, f)
json.dump(self.data, f, indent=2)
except Exception:
self.load_data()
-5
View File
@@ -25,11 +25,6 @@ renpy.display.accelerator gen/renpy.display.accelerator.c
renpy.display.quaternion gen/renpy.display.quaternion.c
renpy.uguu.gl gen/renpy.uguu.gl.c
renpy.uguu.uguu gen/renpy.uguu.uguu.c
renpy.gl.gldraw gen/renpy.gl.gldraw.c
renpy.gl.gltexture gen/renpy.gl.gltexture.c
renpy.gl.glenviron_shader gen/renpy.gl.glenviron_shader.c
renpy.gl.glrtt_copy gen/renpy.gl.glrtt_copy.c
renpy.gl.glrtt_fbo gen/renpy.gl.glrtt_fbo.c
renpy.gl2.gl2mesh gen/renpy.gl2.gl2mesh.c
renpy.gl2.gl2mesh2 gen/renpy.gl2.gl2mesh2.c
renpy.gl2.gl2mesh3 gen/renpy.gl2.gl2mesh3.c
-6
View File
@@ -174,12 +174,6 @@ cython("renpy.display.quaternion", libs=[ 'm' ])
cython("renpy.uguu.gl", libs=sdl)
cython("renpy.uguu.uguu", libs=sdl)
cython("renpy.gl.gldraw", libs=sdl)
cython("renpy.gl.gltexture", libs=sdl)
cython("renpy.gl.glenviron_shader", libs=sdl)
cython("renpy.gl.glrtt_copy", libs=sdl)
cython("renpy.gl.glrtt_fbo", libs=sdl)
cython("renpy.gl2.gl2mesh")
cython("renpy.gl2.gl2mesh2")
cython("renpy.gl2.gl2mesh3")
-2
View File
@@ -223,7 +223,6 @@ backup_blacklist = {
"renpy.test.testmouse",
"renpy.test.testparser",
"renpy.gl2",
"renpy.gl",
"renpycoverage",
}
@@ -479,7 +478,6 @@ def import_all():
sys.modules[pystr('renpy.display.text')] = renpy.text.text
import renpy.gl
import renpy.gl2
import renpy.display.layout
-1
View File
@@ -217,7 +217,6 @@ init -1100 python:
if version <= (7, 4, 4):
config.pause_after_rollback = True
config.gl2 = False
config.gl_lod_bias = -1.0
config.who_what_sub_compat = 1
+2 -26
View File
@@ -27,8 +27,7 @@ init -1500:
python:
class _SetRenderer(Action):
"""
Sets the preferred renderer to one of "auto", "angle", "gl", or
"sw".
Sets the preferred renderer.
"""
def __init__(self, renderer):
@@ -95,24 +94,6 @@ init -1500:
action _SetRenderer("auto")
style_suffix "radio_button"
if not config.gl2:
if gl:
textbutton _("Force GL Renderer"):
action _SetRenderer("gl")
style_suffix "radio_button"
if angle:
textbutton _("Force ANGLE Renderer"):
action _SetRenderer("angle")
style_suffix "radio_button"
if gles:
textbutton _("Force GLES Renderer"):
action _SetRenderer("gles")
style_suffix "radio_button"
if gl:
textbutton _("Force GL2 Renderer"):
action _SetRenderer("gl2")
@@ -349,16 +330,11 @@ init -1500 python:
renderer_info = renpy.get_renderer_info()
# Software renderer check.
# Software renderer check.
if config.renderer != "sw" and renderer_info["renderer"] == "sw":
problem = "sw"
allow_continue = False
# Game require gl2 that wasn't initialized.
elif config.gl2 and not renderer_info.get("models", False):
problem = "gl2"
allow_continue = False
if problem is None:
return
+4 -18
View File
@@ -1201,24 +1201,15 @@ class Interface(object):
renpy.config.renderer = renderer
if renpy.android or renpy.ios or renpy.emscripten:
renderers = [ "gles" ]
renderers = [ "gles2" ]
elif renpy.windows:
renderers = [ "gl", "angle", "gles" ]
renderers = [ "gl2", "angle2", "gles2" ]
else:
renderers = [ "gl", "gles" ]
gl2_renderers = [ ]
for i in [ "gl", "angle", "gles" ]:
if i in renderers:
gl2_renderers.append(i + "2")
renderers = gl2_renderers + renderers
renderers = [ "gl2", "gles2" ]
# Prevent a performance warning if the renderer
# is taken from old persistent data.
if renderer not in gl2_renderers and (renpy.macintosh or renpy.android or renpy.config.gl2):
if renderer not in renderers:
renderer = "auto"
# Software renderer is the last hope for PC .
@@ -1254,10 +1245,6 @@ class Interface(object):
return False
make_draw("gl", "renpy.gl.gldraw", "GLDraw", "gl")
make_draw("angle", "renpy.gl.gldraw", "GLDraw", "angle")
make_draw("gles", "renpy.gl.gldraw", "GLDraw", "gles")
make_draw("gl2", "renpy.gl2.gl2draw", "GL2Draw", "gl2")
make_draw("angle2", "renpy.gl2.gl2draw", "GL2Draw", "angle2")
make_draw("gles2", "renpy.gl2.gl2draw", "GL2Draw", "gles2")
@@ -1364,7 +1351,6 @@ class Interface(object):
raise Exception("Could not set video mode.")
renpy.session["renderer"] = draw.info["renderer"]
renpy.game.persistent._gl2 = renpy.config.gl2
if renpy.android:
android.init()
-2
View File
@@ -60,8 +60,6 @@ def init_display():
The minimum amount of code required to init the display.
"""
renpy.config.gl2 = getattr(renpy.game.persistent, "_gl2", True)
# Ensure we have correctly-typed preferences.
renpy.game.preferences.check()
-17
View File
@@ -1,17 +0,0 @@
from __future__ import division, absolute_import, with_statement, print_function, unicode_literals
from renpy.compat import PY2, basestring, bchr, bord, chr, open, pystr, range, round, str, tobytes, unicode # *
import renpy
renpy.update_path()
# Generated by scripts/relative_imports.py, do not edit below this line.
if 1 == 0:
from . import gldraw
from . import glenviron_shader
from . import glfunctions
from . import glrtt_copy
from . import glrtt_fbo
from . import gltexture
-96
View File
@@ -1,96 +0,0 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
#
# 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.
from renpy.display.matrix cimport Matrix, Matrix2D
cimport renpy.display.render as render
cdef class Environ
cdef class GLDraw:
cdef bint gles
cdef bint angle
cdef bint did_init
cdef bint did_texture_test
cdef Environ environ
cdef public object rtt
cdef object window
cdef tuple virtual_size
cdef public tuple physical_size
cdef public tuple drawable_size
cdef public tuple virtual_box
cdef public tuple physical_box
cdef object texture_cache
cdef double last_redraw_time
cdef double redraw_period
cdef public dict info
cdef object old_fullscreen
cdef public object fullscreen_surface
cdef object display_info
cdef tuple clip_cache
cdef bint fast_dissolve
cdef tuple default_clip
cdef bint did_render_to_texture
cdef float dpi_scale
cdef object ready_texture_queue
cdef public tuple clip_rtt_box
# The number of drawable pixels per virtual pixel.
cdef public object draw_per_virt
# Matrices that transform drawable to virtual, and vice versa.
cdef public Matrix virt_to_draw
cdef public Matrix draw_to_virt
cdef public int fast_redraw_frames
cpdef set_clip(GLDraw self, tuple clip)
cpdef int draw_render_textures(
GLDraw self,
object what,
bint non_aligned) except 1
cpdef int draw_transformed(
GLDraw self,
object what,
tuple clip,
double xo,
double yo,
double alpha,
double over,
Matrix reverse,
bint nearest,
bint subpixel) except 1
cdef class Environ:
cdef void blit(self)
cdef void blend(self, double fraction)
cdef void imageblend(self, double fraction, int ramp)
cdef void set_vertex(self, float *vertices)
cdef void set_texture(self, int unit, float *coords)
cdef void set_color(self, float r, float g, float b, float a)
cdef void set_clip(self, tuple clip_box, GLDraw draw)
cdef void unset_clip(self, GLDraw draw)
cdef void ortho(self, double left, double right, double bottom, double top, double near, double far)
cdef void viewport(self, int x, int y, int width, int height)
-1417
View File
File diff suppressed because it is too large Load Diff
-671
View File
@@ -1,671 +0,0 @@
#cython: profile=False
# Copyright 2004-2024 Tom Rothamel <pytom@bishoujo.us>
#
# 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.
from __future__ import print_function
from renpy.uguu.gl cimport *
from renpy.gl.gldraw cimport *
cdef int round(double d):
return <int> (d + .5)
GLES_PORTABILITY = """\
#ifdef GL_ES
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
# else
precision mediump float;
# endif
#endif
"""
VERTEX_SHADER1 = GLES_PORTABILITY + """\
uniform mat4 Projection;
attribute vec4 Vertex;
attribute vec2 VertexTexCoord0;
varying vec2 TexCoord0;
varying vec2 pos;
void main() {
TexCoord0 = VertexTexCoord0;
pos = Vertex.xy;
gl_Position = Projection * Vertex;
}
"""
VERTEX_SHADER2 = GLES_PORTABILITY + """\
uniform mat4 Projection;
attribute vec4 Vertex;
attribute vec2 VertexTexCoord0;
attribute vec2 VertexTexCoord1;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 pos;
void main() {
TexCoord0 = VertexTexCoord0;
TexCoord1 = VertexTexCoord1;
pos = Vertex.xy;
gl_Position = Projection * Vertex;
}
"""
VERTEX_SHADER3 = GLES_PORTABILITY + """\
uniform mat4 Projection;
attribute vec4 Vertex;
attribute vec2 VertexTexCoord0;
attribute vec2 VertexTexCoord1;
attribute vec2 VertexTexCoord2;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 TexCoord2;
varying vec2 pos;
void main() {
TexCoord0 = VertexTexCoord0;
TexCoord1 = VertexTexCoord1;
TexCoord2 = VertexTexCoord2;
pos = Vertex.xy;
gl_Position = Projection * Vertex;
}
"""
BLIT_SHADER = GLES_PORTABILITY + """\
uniform vec4 Color;
uniform sampler2D tex0;
varying vec2 TexCoord0;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
vec4 color0 = texture2D(tex0, TexCoord0.st);
gl_FragColor = color0 * Color;
}
"""
BLIT_CLIP_SHADER = GLES_PORTABILITY + """\
uniform vec4 Color;
uniform sampler2D tex0;
varying vec2 TexCoord0;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
discard;
}
vec4 color0 = texture2D(tex0, TexCoord0.st);
gl_FragColor = color0 * Color;
}
"""
BLEND_SHADER = GLES_PORTABILITY + """\
uniform vec4 Color;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float done;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
vec4 color0 = texture2D(tex0, TexCoord0.st);
vec4 color1 = texture2D(tex1, TexCoord1.st);
gl_FragColor = mix(color0, color1, done) * Color;
}
"""
BLEND_CLIP_SHADER = GLES_PORTABILITY + """\
uniform vec4 Color;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float done;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
discard;
}
vec4 color0 = texture2D(tex0, TexCoord0.st);
vec4 color1 = texture2D(tex1, TexCoord1.st);
gl_FragColor = mix(color0, color1, done) * Color;
}
"""
IMAGEBLEND_SHADER = GLES_PORTABILITY + """\
uniform vec4 Color;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform float offset;
uniform float multiplier;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 TexCoord2;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
vec4 color0 = texture2D(tex0, TexCoord0.st);
vec4 color1 = texture2D(tex1, TexCoord1.st);
vec4 color2 = texture2D(tex2, TexCoord2.st);
float a = clamp((color0.a + offset) * multiplier, 0.0, 1.0);
gl_FragColor = mix(color1, color2, a) * Color;
}
"""
IMAGEBLEND_CLIP_SHADER = GLES_PORTABILITY + """\
uniform vec4 Color;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform sampler2D tex2;
uniform float offset;
uniform float multiplier;
varying vec2 TexCoord0;
varying vec2 TexCoord1;
varying vec2 TexCoord2;
varying vec2 pos;
uniform vec2 clip0;
uniform vec2 clip1;
void main()
{
if (pos.x < clip0.x || pos.y < clip0.y || pos.x >= clip1.x || pos.y >= clip1.y) {
discard;
}
vec4 color0 = texture2D(tex0, TexCoord0.st);
vec4 color1 = texture2D(tex1, TexCoord1.st);
vec4 color2 = texture2D(tex2, TexCoord2.st);
float a = clamp((color0.a + offset) * multiplier, 0.0, 1.0);
gl_FragColor = mix(color1, color2, a) * Color;
}
"""
def check_status(shader, handle, type):
"""
Checks the status of a shader or program. If it fails, then an
exception is raised.
"""
cdef GLint status = 0
cdef GLint log_length = 0
if shader:
glGetShaderiv(handle, type, &status)
else:
glGetProgramiv(handle, type, &status)
if status == 1: # 0 for problems.
return
if shader:
glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &log_length)
else:
glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &log_length)
log = ' ' * log_length
if shader:
glGetShaderInfoLog(handle, log_length, &log_length, <char *> log)
else:
glGetProgramInfoLog(handle, log_length, &log_length, <char *> log)
raise Exception("Shader error: %s" % log)
def compile_shader(kind, source):
"""
Allocates and compiles a shader.
"""
source = source.encode("utf-8")
cdef char *sourceptr = <char *> source
cdef int lensource = len(source)
handle = glCreateShader(kind)
glShaderSource(handle, 1, <const GLchar * const *> &sourceptr, &lensource)
glCompileShader(handle)
check_status(True, handle, GL_COMPILE_STATUS)
return handle
def compile_program(vertex, fragment):
"""
Compiles a pair of shaders into a program.
"""
vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex)
fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment)
program = glCreateProgram()
glAttachShader(program, vertex_shader)
glAttachShader(program, fragment_shader)
glLinkProgram(program)
check_status(False, program, GL_LINK_STATUS)
glUseProgram(program)
glDeleteShader(vertex_shader)
glDeleteShader(fragment_shader)
return program
cdef class Program(object):
"""
Encapsulates a program.
"""
cdef GLuint program
# Attributes.
cdef GLint Vertex
cdef GLint VertexTexCoord0
cdef GLint VertexTexCoord1
cdef GLint VertexTexCoord2
# Uniforms.
cdef GLint Projection
cdef GLint Color
cdef GLint tex0
cdef GLint tex1
cdef GLint tex2
cdef GLint clip0
cdef GLint clip1
cdef GLint offset
cdef GLint multiplier
cdef GLint done
def __init__(self, vertex, fragment):
self.program = compile_program(vertex, fragment)
self.Vertex = glGetAttribLocation(self.program, "Vertex")
self.VertexTexCoord0 = glGetAttribLocation(self.program, "VertexTexCoord0")
self.VertexTexCoord1 = glGetAttribLocation(self.program, "VertexTexCoord1")
self.VertexTexCoord2 = glGetAttribLocation(self.program, "VertexTexCoord2")
self.Projection = glGetUniformLocation(self.program, "Projection")
self.tex0 = glGetUniformLocation(self.program, "tex0")
self.tex1 = glGetUniformLocation(self.program, "tex1")
self.tex2 = glGetUniformLocation(self.program, "tex2")
self.offset = glGetUniformLocation(self.program, "offset")
self.multiplier = glGetUniformLocation(self.program, "multiplier")
self.done = glGetUniformLocation(self.program, "done")
self.Color = glGetUniformLocation(self.program, "Color")
self.clip0 = glGetUniformLocation(self.program, "clip0")
self.clip1 = glGetUniformLocation(self.program, "clip1")
def disable_attribs(self):
# Disable the vertex attributes used by this program.
if self.Vertex != -1:
glDisableVertexAttribArray(self.Vertex)
if self.VertexTexCoord0 != -1:
glDisableVertexAttribArray(self.VertexTexCoord0)
if self.VertexTexCoord1 != -1:
glDisableVertexAttribArray(self.VertexTexCoord1)
if self.VertexTexCoord2 != -1:
glDisableVertexAttribArray(self.VertexTexCoord2)
def delete(self):
glDeleteProgram(self.program)
cdef class ShaderEnviron(Environ):
"""
This is an environment that uses shaders.
"""
cdef Program program
cdef float projection[16]
cdef Program blit_program
cdef Program blend_program
cdef Program imageblend_program
cdef Program blit_clip_program
cdef Program blend_clip_program
cdef Program imageblend_clip_program
cdef bint clipping
cdef double clip_x0
cdef double clip_y0
cdef double clip_x1
cdef double clip_y1
cdef int viewport_x
cdef int viewport_y
cdef int viewport_w
cdef int viewport_h
def init(self):
self.blit_program = Program(VERTEX_SHADER1, BLIT_SHADER)
self.blit_clip_program = Program(VERTEX_SHADER1, BLIT_CLIP_SHADER)
self.blend_program = Program(VERTEX_SHADER2, BLEND_SHADER)
self.blend_clip_program = Program(VERTEX_SHADER2, BLEND_CLIP_SHADER)
self.imageblend_program = Program(VERTEX_SHADER3, IMAGEBLEND_SHADER)
self.imageblend_clip_program = Program(VERTEX_SHADER3, IMAGEBLEND_CLIP_SHADER)
# The current program.
self.program = None
def deinit(self):
"""
Called before changing the GL context.
"""
if self.program is not None:
self.program.disable_attribs()
self.program = None
self.blit_program.delete()
self.blend_program.delete()
self.imageblend_program.delete()
def activate(self, Program program):
if self.program is not None:
self.program.disable_attribs()
self.program = program
glUseProgram(program.program)
glUniformMatrix4fv(program.Projection, 1, GL_FALSE, self.projection)
if self.clipping:
glUniform2f(program.clip0, self.clip_x0 - .01, self.clip_y0 - .01)
glUniform2f(program.clip1, self.clip_x1 + .01, self.clip_y1 + .01)
cdef void blit(self):
if self.clipping:
program = self.blit_clip_program
else:
program = self.blit_program
if self.program is not program:
self.activate(program)
glUniform1i(program.tex0, 0)
cdef void blend(self, double fraction):
if self.clipping:
program = self.blend_clip_program
else:
program = self.blend_program
if self.program is not program:
self.activate(program)
glUniform1i(program.tex0, 0)
glUniform1i(program.tex1, 1)
glUniform1f(program.done, fraction)
cdef void imageblend(self, double fraction, int ramp):
if self.clipping:
program = self.imageblend_clip_program
else:
program = self.imageblend_program
if self.program is not program:
self.activate(program)
glUniform1i(program.tex0, 0)
glUniform1i(program.tex1, 1)
glUniform1i(program.tex2, 2)
# Prevent a DBZ if the user gives us a 0 ramp.
if ramp < 1:
ramp = 1
# Compute the offset to apply to the alpha.
start = -1.0
end = ramp / 256.0
offset = start + ( end - start) * fraction
# Setup the multiplier and the offset.
glUniform1f(program.multiplier, 256.0 / ramp)
glUniform1f(program.offset, offset)
cdef void set_vertex(self, float *vertices):
glEnableVertexAttribArray(self.program.Vertex)
glVertexAttribPointer(self.program.Vertex, 2, GL_FLOAT, GL_FALSE, 0, <GLubyte *> vertices)
cdef void set_texture(self, int unit, float *coords):
cdef tex
if unit == 0:
tex = self.program.VertexTexCoord0
elif unit == 1:
tex = self.program.VertexTexCoord1
elif unit == 2:
tex = self.program.VertexTexCoord2
else:
return
if tex < 0:
return
if coords != NULL:
glVertexAttribPointer(tex, 2, GL_FLOAT, GL_FALSE, 0, <GLubyte *> coords)
glEnableVertexAttribArray(tex)
else:
glDisableVertexAttribArray(tex)
cdef void set_color(self, float r, float g, float b, float a):
glUniform4f(self.program.Color, r, g, b, a)
cdef void ortho(self, double left, double right, double bottom, double top, double near, double far):
self.projection[ 0] = 2 / (right - left)
self.projection[ 4] = 0
self.projection[ 8] = 0
self.projection[12] = -(right + left) / (right - left)
self.projection[ 1] = 0
self.projection[ 5] = 2 / (top - bottom)
self.projection[ 9] = 0
self.projection[13] = -(top + bottom) / (top - bottom)
self.projection[ 2] = 0
self.projection[ 6] = 0
self.projection[10] = -2 / (far - near)
self.projection[14] = -(far + near) / (far - near)
self.projection[ 3] = 0
self.projection[ 7] = 0
self.projection[11] = 0
self.projection[15] = 1
if self.program is not None:
self.program.disable_attribs()
self.program = None
cdef void project(self, x, y, z, double *rv_x, double *rv_y, double *rv_z):
"""
Given a point, projects it using the projection.
"""
rv_x[0] = x * self.projection[0] + y * self.projection[4] + z * self.projection[8] + self.projection[12]
rv_y[0] = x * self.projection[1] + y * self.projection[5] + z * self.projection[9] + self.projection[13]
rv_z[0] = x * self.projection[2] + y * self.projection[6] + z * self.projection[10] + self.projection[14]
cdef void set_clip(self, tuple clip_box, GLDraw draw):
cdef double minx, miny, maxx, maxy, z
cdef double vwidth, vheight
cdef double px, py, pw, ph
cdef int cx, cy, cw, ch
cdef int psw, psh
if clip_box == draw.default_clip:
self.unset_clip(draw)
return
minx, miny, maxx, maxy = clip_box
psw, psh = draw.physical_size
# The clipping box.
self.clipping = True
self.clip_x0 = minx
self.clip_y0 = miny
self.clip_x1 = maxx
self.clip_y1 = maxy
# Set the scissor rectangle to be slightly larger than the
# clipping box. This ensures everything that needs to be drawn
# is drawn, and we don't spend a lot of time shading clipped
# fragments.
if draw.clip_rtt_box is None:
z = 0
# Project to normalized coordinates.
self.project(minx, miny, z, &minx, &miny, &z)
self.project(maxx, maxy, z, &maxx, &maxy, &z)
# Convert to window coordinates.
minx = (minx + 1) * self.viewport_w / 2 + self.viewport_x
maxx = (maxx + 1) * self.viewport_w / 2 + self.viewport_x
miny = (miny + 1) * self.viewport_h / 2 + self.viewport_y
maxy = (maxy + 1) * self.viewport_h / 2 + self.viewport_y
# Increase the bounding box, to ensure every relevant pixel is
# in it. The shader will take care of enforcing the actual box.
minx -= 1
maxx += 1
miny += 1
maxy -= 1
if minx < 0:
minx = 0
if miny < 0:
miny = 0
glEnable(GL_SCISSOR_TEST)
glScissor(<GLint> round(minx), <GLint> round(maxy), <GLint> round(maxx - minx), <GLsizei> round(miny - maxy))
else:
cx, cy, cw, ch = draw.clip_rtt_box
glEnable(GL_SCISSOR_TEST)
glScissor(<GLint> round(minx - cx), <GLint> round(miny - cy), <GLint> round(maxx - minx), <GLint> round(maxy - miny))
if self.program is not None:
self.program.disable_attribs()
self.program = None
cdef void unset_clip(self, GLDraw draw):
glDisable(GL_SCISSOR_TEST)
self.clipping = False
self.clip_x0 = 0
self.clip_y0 = 0
self.clip_x1 = 65535
self.clip_y1 = 65535
if self.program is not None:
self.program.disable_attribs()
self.program = None
cdef void viewport(self, int x, int y, int width, int height):
glViewport(x, y, width, height)
self.viewport_x = x
self.viewport_y = y
self.viewport_w = width
self.viewport_h = height
-59
View File
@@ -1,59 +0,0 @@
# This file has been automatically generated by module/uguu/generate_required_functions.py,
# please do not edit it by hand.
from __future__ import division, absolute_import, with_statement, print_function, unicode_literals
from renpy.compat import PY2, basestring, bchr, bord, chr, open, pystr, range, round, str, tobytes, unicode # *
required_functions = [
"glActiveTexture",
"glAttachShader",
"glBindFramebuffer",
"glBindTexture",
"glBlendFunc",
"glClear",
"glClearColor",
"glCompileShader",
"glCopyTexImage2D",
"glCopyTexSubImage2D",
"glCreateProgram",
"glCreateShader",
"glDeleteFramebuffers",
"glDeleteProgram",
"glDeleteShader",
"glDeleteTextures",
"glDisable",
"glDisableVertexAttribArray",
"glDrawArrays",
"glEnable",
"glEnableVertexAttribArray",
"glFinish",
"glFramebufferTexture2D",
"glGenFramebuffers",
"glGenTextures",
"glGetAttribLocation",
"glGetError",
"glGetIntegerv",
"glGetProgramInfoLog",
"glGetProgramiv",
"glGetShaderInfoLog",
"glGetShaderiv",
"glGetString",
"glGetUniformLocation",
"glLinkProgram",
"glReadPixels",
"glScissor",
"glShaderSource",
"glTexImage2D",
"glTexParameteri",
"glTexSubImage2D",
"glUniform1f",
"glUniform1i",
"glUniform2f",
"glUniform4f",
"glUniformMatrix4fv",
"glUseProgram",
"glVertexAttribPointer",
"glViewport",
]
-72
View File
@@ -1,72 +0,0 @@
#@PydevCodeAnalysisIgnore
#cython: profile=False
# Copyright 2004-2024 Tom Rothamel <pytom@bishoujo.us>
#
# 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.
from __future__ import print_function
from renpy.uguu.gl cimport *
from renpy.gl.gldraw cimport *
from renpy.gl.gldraw import Rtt
class CopyRtt(Rtt):
"""
This class uses texture copying to implement Render-to-texture.
"""
def init(self):
return
def deinit(self):
return
def render(self, Environ environ, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
environ.viewport(0, 0, w, h)
environ.ortho(x, x + w, y, y + h, -1, 1)
draw_func(x, y, w, h)
glBindTexture(GL_TEXTURE_2D, texture)
glCopyTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
0,
0,
w,
h)
def end(self):
"""
This is called when a Render-to-texture session ends.
"""
def get_size_limit(self, dimension):
return dimension
-115
View File
@@ -1,115 +0,0 @@
#@PydevCodeAnalysisIgnore
#cython: profile=False
# Copyright 2004-2024 Tom Rothamel <pytom@bishoujo.us>
#
# 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.
from __future__ import print_function
from renpy.uguu.gl cimport *
from renpy.gl.gldraw cimport *
from renpy.gl.gldraw import Rtt
import renpy
# The framebuffer object we use.
cdef GLuint fbo
# The root framebuffer.
cdef GLint root_fbo
# The renderbuffer object we use.
cdef GLuint texture
class FboRtt(Rtt):
"""
This class uses texture copying to implement Render-to-texture.
"""
def init(self):
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &root_fbo);
renpy.display.log.write("Root FBO is: %d", root_fbo)
glGenFramebuffers(1, &fbo)
glGenTextures(1, &texture)
cdef int i
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &i)
self.size_limit = min(i, 2048)
renpy.display.log.write("FBO Maximum Texture Size: %d", self.size_limit)
glBindTexture(GL_TEXTURE_2D, texture)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.size_limit, self.size_limit, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL)
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
texture,
0)
glBindFramebuffer(GL_FRAMEBUFFER, root_fbo)
def deinit(self):
"""
Called before changing the GL context.
"""
glBindFramebuffer(GL_FRAMEBUFFER, root_fbo)
glDeleteFramebuffers(1, &fbo)
glDeleteTextures(1, &texture)
def begin(self):
"""
This function should be called when a Render-to-texture
session begins. It's responsible for setting the GPU to
RTT mode.
"""
def render(self, Environ environ, texture, x, y, w, h, draw_func):
"""
This function is called to trigger a rendering to a texture.
`x`, `y`, `w`, and `h` specify the location and dimensions of
the sub-image to render to the texture. `draw_func` is called
to render the texture.
"""
try:
glBindFramebuffer(GL_FRAMEBUFFER, fbo)
environ.viewport(0, 0, w, h)
environ.ortho(x, x + w, y, y + h, -1, 1)
draw_func(x, y, w, h)
glBindTexture(GL_TEXTURE_2D, texture)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL)
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, w, h, 0)
finally:
glBindFramebuffer(GL_FRAMEBUFFER, root_fbo)
def get_size_limit(self, dimension):
return self.size_limit
-104
View File
@@ -1,104 +0,0 @@
# Copyright 2004-2014 Tom Rothamel <pytom@bishoujo.us>
#
# 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.
from renpy.display.matrix cimport Matrix
cimport renpy.display.render as render
from renpy.gl.gldraw cimport Environ
cdef class TextureCore:
cdef public int width
cdef public int height
cdef public int generation
cdef public unsigned int number
cdef unsigned int format
cdef double xmul
cdef double xadd
cdef double ymul
cdef double yadd
cdef object premult
cdef tuple premult_size
cdef int premult_left
cdef int premult_right
cdef int premult_top
cdef int premult_bottom
cdef bint nearest
cdef public list free_list
cdef void make_ready(TextureCore)
cdef void make_nearest(TextureCore)
cdef void make_linear(TextureCore)
cpdef int allocate(TextureCore)
cdef public object debug
cdef class TextureGrid:
cdef object __weakref__
cdef public int width
cdef public int height
cdef list rows
cdef list columns
cdef list tiles # list of lists.
cdef public TextureGrid half_cache
cpdef void make_ready(self, bint nearest)
cdef public object debug
cdef public bint ready
cpdef blit(
TextureGrid tg,
double sx,
double sy,
Matrix transform,
double alpha,
double over,
Environ environ,
bint nearest)
cpdef blend(
TextureGrid tg0,
TextureGrid tg1,
double sx,
double sy,
Matrix transform,
double alpha,
double over,
double fraction,
Environ environ,
bint nearest)
cpdef imageblend(
TextureGrid tg0,
TextureGrid tg1,
TextureGrid tg2,
double sx,
double sy,
Matrix transform,
double alpha,
double over,
double fraction,
int ramp,
Environ environ,
bint nearest)
File diff suppressed because it is too large Load Diff
-3
View File
@@ -88,9 +88,6 @@ def init():
if live2dmodel is None:
raise Exception("Live2D has not been built.")
if not renpy.config.gl2:
raise Exception("Live2D requires that config.gl2 be True.")
if renpy.emscripten:
raise Exception("Live2D is not supported the web platform.")
+1 -2
View File
@@ -2,5 +2,4 @@
cd $(dirname $(dirname $(readlink -f $0)))
nice lib/py2-linux-x86_64/python add.py --real "$@"
nice lib/py3-linux-x86_64/python add.py --real "$@"
lib/py3-linux-x86_64/python add.py --real "$@"
-2
View File
@@ -16,7 +16,5 @@ sleep 2
rpy pull
rpy build --python 3
rpy build --python 2
lib/py3-linux-x86_64/python distribute.py
lib/py2-linux-x86_64/python distribute.py
+294 -62
View File
@@ -1,5 +1,6 @@
from __future__ import print_function, unicode_literals
from __future__ import print_function, unicode_literals, annotations
import ast
import inspect
import re
import collections
@@ -10,11 +11,14 @@ import io
import os
import textwrap
import pprint
import types
from typing import Any, Iterable, Literal
try:
import builtins
except ImportError:
import __builtin__ as builtins
import __builtin__ as builtins # type: ignore
# Additional keywords in the Ren'Py script language.
SCRIPT_KEYWORDS = """\
@@ -203,20 +207,17 @@ def write_keywords(srcdir='source'):
# A map from filename to a list of lines that are supposed to go into
# that file.
line_buffer = collections.defaultdict(list)
line_buffer = collections.defaultdict[str, list[str]](list)
# A map from id(o) to the names it's documented under.
documented = collections.defaultdict(list)
# This keeps all objectsd we see alive, to prevent duplicates in documented.
documented_list = [ ]
documented = collections.defaultdict[int, list[str]](list)
def getdoc(o):
"""
Returns the docstring for `o`, but unlike inspect.getdoc, does not get
values from base classes if absent (and it's faster too).
Will still get the inherited docstring for a non-overridden method in a
subclass (because the method object is the same as the base classe's).
subclass (because the method object is the same as the base classes).
"""
doc = getattr(o, "__doc__", None)
@@ -229,23 +230,189 @@ def getdoc(o):
# The docstring for object.__init__ - which we don't want to pass for one of our classes's
objinidoc = getdoc(object.__init__)
_file_trees: dict[str, ast.Module] = {}
def scan(name, o, prefix="", inclass=False):
def scan_pep224(prefix: str, o_name: str | None, o: type | types.ModuleType, /):
"""
Scan for PEP-224 docstrings for variables of `o` (either a module or class).
For classes also scans its __init__ method.
Documented variables are then scanned for Sphinx docstrings and added to the
line buffer.
"""
if isinstance(o, types.ModuleType):
# No variables in namespace packages.
if o.__spec__.origin is None:
return
module_name = o.__name__
elif isinstance(o, type):
module_name = o.__module__
if inspect.isclass(o):
if issubclass(o, (renpy.store.Action,
renpy.store.BarValue,
renpy.store.InputValue)):
doc_type = "function"
else:
doc_type = "class"
elif inclass:
doc_type = "method"
else:
doc_type = "function"
raise TypeError(f"Expected a class or module, got {o!r}")
# The section it's going into.
section = None
fn = inspect.getfile(o)
# Can't read Cython files.
if fn == "built-in":
return
# No source for Ren'Py store modules.
if module_name in renpy.python.store_modules:
return
if fn in _file_trees:
tree = _file_trees[fn]
else:
try:
# Maybe raise exceptions with appropriate message
# before using cleaned doc_obj.source
source, _ = inspect.findsource(o)
tree = ast.parse("".join(source), fn)
except (OSError, TypeError, SyntaxError) as exc:
print(f"Warning: couldn't read PEP-224 variable docstrings from {o!r}: {exc}")
return
_file_trees[fn] = tree
def scan(tree: ast.AST, in_init_func: bool):
from itertools import tee
a, b = \
tee(ast.iter_child_nodes(tree))
next(b, None)
for assign_node, str_node in zip(a, b):
if not (isinstance(str_node, ast.Expr) and
isinstance(str_node.value, ast.Constant) and
isinstance(str_node.value.value, str)):
continue
if isinstance(assign_node, ast.Assign) and len(assign_node.targets) == 1:
target = assign_node.targets[0]
elif isinstance(assign_node, ast.AnnAssign):
target = assign_node.target
else:
continue
if (not in_init_func) and isinstance(target, ast.Name):
name = target.id
elif (in_init_func and
isinstance(target, ast.Attribute) and
isinstance(target.value, ast.Name) and
target.value.id == 'self'):
name = target.attr
else:
continue
docstring = inspect.cleandoc(str_node.value.value)
if not docstring:
continue
default = None
if assign_node.value is not None:
try:
default = ast.unparse(assign_node.value)
except Exception:
pass
if o_name is not None:
name = f"{o_name}{name}"
vars[name] = docstring, default
return vars
vars: dict[str, tuple[str, str | None]] = {}
if isinstance(o, types.ModuleType):
default_doc_type = "var"
scan(tree, False)
elif isinstance(o, type):
default_doc_type = "attribute"
class ClassFoundException(Exception):
def __init__(self, class_def: ast.ClassDef):
self.class_def = class_def
class ClassFinder(ast.NodeVisitor):
def __init__(self):
self.stack = []
def visit_FunctionDef(self, node):
self.stack.append(node.name)
self.stack.append('<locals>')
self.generic_visit(node)
self.stack.pop()
self.stack.pop()
visit_AsyncFunctionDef = visit_FunctionDef # type: ignore
def visit_ClassDef(self, node):
self.stack.append(node.name)
if o.__qualname__ == '.'.join(self.stack):
raise ClassFoundException(node)
self.generic_visit(node)
self.stack.pop()
try:
ClassFinder().visit(tree)
except ClassFoundException as e:
scan(e.class_def, False)
# For classes add instance variables defined in __init__
# Get the *last* __init__ node in case it is preceded by @overloads.
for node in reversed(e.class_def.body):
if isinstance(node, ast.FunctionDef) and node.name == '__init__':
scan(node, True)
break
else:
print(f"Warning: couldn't find class {o.__qualname__} in {fn}")
return
for name, (docstring, default) in vars.items():
(
lines,
doc_type,
section,
name,
explicit_default,
) = inspect_doc(name, docstring, default)
if section is None:
continue
if doc_type is None:
doc_type = default_doc_type
if explicit_default is not None:
default = explicit_default
if default is None:
default = "..."
# Put it into the line buffer.
lb = line_buffer[section]
lb.append(f"{prefix}.. {doc_type}:: {name} = {default}")
for l in lines:
lb.append(f"{prefix} {l}")
lb.append(prefix)
def scan(name: str, o: Any, prefix="", inclass=False):
"""
Given an object `o`, scans it for sphinx doc string and adds it to the
line buffer and list of documented objects.
"""
# The formatted arguments.
args = None
@@ -256,52 +423,56 @@ def scan(name, o, prefix="", inclass=False):
if not doc:
return
if doc[0] == ' ':
print("Bad docstring for ", name, repr(doc))
# Cython-generated docstrings start with the function and arguments.
if re.match(r'[\w\.]+\(', doc):
orig = doc
sig, _, doc = doc.partition("\n\n")
doc = textwrap.dedent(doc)
if "(" in sig:
args = "(" + sig.partition("(")[2]
if not doc:
return
# Break up the doc string, scan it for specials.
lines = [ ]
for l in doc.split("\n"):
m = re.match(r':doc: *(\w+) *(\w+)?', l)
if m:
section = m.group(1)
if m.group(2):
doc_type = m.group(2)
continue
m = re.match(r':args: *(.*)', l)
if m:
args = m.group(1)
continue
m = re.match(r':name: *(\S+)', l)
if m:
if name != m.group(1):
return
continue
lines.append(l)
(
lines,
doc_type,
section,
new_name,
explicit_args,
) = inspect_doc(name, doc, args)
if section is None:
return
if args is None:
# Don't add documentation via this path.
if new_name != name:
return
if inspect.isclass(o):
if issubclass(o, (renpy.store.Action,
renpy.store.BarValue,
renpy.store.InputValue)):
o_type = "function"
else:
o_type = "class"
elif inclass:
o_type = "method"
else:
o_type = "function"
if doc_type is None:
doc_type = o_type
# Forbid to add functions/classes/method as variables.
elif doc_type not in ("function", "class", "method"):
print(f"Warning: {name} is a {o_type} but documented as {doc_type}.")
return
if explicit_args is not None:
args = explicit_args
if args is None:
# Get the arguments.
if inspect.isclass(o):
init = getattr(o, "__init__", None)
@@ -324,16 +495,19 @@ def scan(name, o, prefix="", inclass=False):
args = inspect.signature(o)
else:
print("Warning: %s has section but not args." % name)
print(f"Warning: {name} has section but not args.")
return
# Format the arguments.
if args is not None:
if args.parameters and next(iter(args.parameters)) == "self":
pars = iter(args.parameters.values())
# Skip 'self' in methods.
pars = iter(args.parameters.values())
if "self" in args.parameters:
next(pars)
args = args.replace(parameters=pars)
# Strip annotations, at least for now.
pars = (p.replace(annotation=p.empty) for p in pars)
args = args.replace(parameters=list(pars))
args = str(args)
else:
@@ -342,30 +516,88 @@ def scan(name, o, prefix="", inclass=False):
# Put it into the line buffer.
lb = line_buffer[section]
lb.append(prefix + ".. %s:: %s%s" % (doc_type, name, args))
lb.append(f"{prefix}.. {doc_type}:: {name}{args}")
for l in lines:
lb.append(prefix + " " + l)
lb.append(f"{prefix} {l}")
lb.append(prefix + "")
lb.append(prefix)
if inspect.isclass(o):
if (name not in [ "Matrix", "OffsetMatrix", "RotateMatrix", "ScaleMatrix" ]):
# Scan for documented attributes in the class first.
scan_pep224(prefix + " ", None, o)
# Then for other classes and methods.
for i in dir(o):
scan(i, getattr(o, i), prefix + " ", inclass=True)
if name == "identity":
raise Exception("identity")
documented_list.append(o)
documented[id(o)].append(name)
def inspect_doc(name: str, doc: str, args_or_default: str | None):
"""
Given doc string after cleandoc, search for special lines
:doc:, :name: and :args: or :default: in it.
Return a (doc lines, doc_type, section, name, args or default) tuple.
"""
if doc[0] == ' ':
print("Bad docstring for ", name, repr(doc))
# Break up the doc string, scan it for specials.
lines: list[str] = [ ]
# The section it's going into.
section: str | None = None
# The kind of doc for sphinx.
doc_type: str | None = None
for l in doc.split("\n"):
m = re.match(r':doc: *(\w+) *(\w+)?', l)
if m:
section = m.group(1)
if m.group(2):
doc_type = m.group(2)
continue
m = re.match(r':args: *(.*)', l)
if m:
args_or_default = m.group(1)
continue
m = re.match(r':default: *(\S+)', l)
if m:
args_or_default = m.group(1)
continue
m = re.match(r':name: *(\S+)', l)
if m:
name = m.group(1)
continue
lines.append(l)
return lines, doc_type, section, name, args_or_default
def scan_section(name, o):
"""
Scans object o. Assumes it has the name name.
"""
# For modules also scan for documented variables.
if isinstance(o, types.ModuleType):
scan_pep224("", name, o)
for n in dir(o):
scan(name + n, getattr(o, n))