Minimal effizienter Cross -Plattform 2D -Grafikmaler in reinem C mit moderner Grafik -API durch die exzellente Sokol GFX -Bibliothek.
Sokol GP oder in kurzer SGP steht für Sokol Graphics Painter.
Sokol GFX ist eine hervorragende Bibliothek für die Rendering mit nicht gemixten Pipelines moderner Grafikkarten. Es ist jedoch zu komplex, um für eine einfache 2D -Zeichnung zu verwenden, und die API ist zu generisch und für das 3D -Rendering spezialisiert. Um 2D -Sachen zu zeichnen, muss der Programmierer normalerweise benutzerdefinierte Shader bei der Verwendung von Sokol GFX einrichten oder seine Sokol GL -zusätzliche Bibliothek verwenden. Sokol GL hat jedoch auch eine API mit 3D -Design, die einige Kosten und Einschränkungen verursacht.
Diese Bibliothek wurde erstellt, um 2D -Primitiven durch Sokol GFX mühelos zu zeichnen. Wenn sie nicht in Betracht gezogen wird, ist sie nur für das 2D -Rendering optimiert. Darüber hinaus verfügt sie über einen automatischen Batch -Optimierer . Weitere Details davon werden nachstehend beschrieben.
Beim Zeichnen der Bibliothek erstellt eine Warteschlange aller vorliegenden Preustiven Zeichnungsbefehlsbefehlsanwälte, wenn ein neuer Zeichnungsbefehl hinzugefügt wird. Der Batch -Optimierer schaut wieder auf die letzten 8 kürzlich durchgeführten Zeichnungsbefehle (dies ist einstellbar).
Auf diese Weise kann der Batch -Optimierer beispielsweise strukturierte Ziehanrufe zusammenführen, auch wenn sie mit anderen zwischengeführten Texturen zwischen ihnen gezogen wurden. Der Effekt ist mehr Effizienz beim Zeichnen, da weniger Ziehanrufe an die GPU geschickt werden.
Diese Bibliothek kann eine Menge Arbeiten der Erstellung eines effizienten 2D -Zeichnungs -Batching -Systems vermeiden, indem sie zur Laufzeit automatisch Zeichnungsanrufe hinter den Kulissen verschmelzen. Daher muss der Programmierer nicht manuell stapelte Zeichnenanrufe verwalten, und er muss auch die Aufrufe von Stapel -Textur zeichnen. Die Bibliothek wird dies ohne die Szenen sortieren.
Der Batching -Algorithmus ist schnell, hat jedoch eine CPU -Komplexität O(n) für jeden neuen Befehl zeichnen, wobei n die Konfiguration SGP_BATCH_OPTIMIZER_DEPTH ist. In Experimenten, 8 verwendet, ist der Standard ein guter Standard, aber Sie möchten möglicherweise je nach Fall unterschiedliche Werte ausprobieren. Die Verwendung von zu hoch zu hohen Werten wird nicht empfohlen, da der Algorithmus möglicherweise zu lange vor frühere Zeichnungsbefehle scannt und dies möglicherweise mehr CPU -Ressourcen verbraucht.
Der Batch -Optimierer kann deaktiviert werden, indem Sie SGP_BATCH_OPTIMIZER_DEPTH auf 0 einstellen. Sie können dies verwenden, um die Auswirkungen zu messen.
Im Beispielverzeichnis dieses Repositorys gibt es ein Benchmark -Beispiel, bei dem das Zeichnen mit dem Bad Optimizer aktiviert/deaktiviert wird. Auf meiner Maschine konnte das Benchmark die Leistung in einem 2,2 -fach -Faktor erhöhen, wenn er aktiviert ist. In einigen privaten Spielprojekten erwies sich die Gewinne des Batch -Optimierers so, dass sie die FPS -Leistung über 1,5x erhöhten, indem nur das Grafik -Backend durch diese Bibliothek ersetzt wurde, ohne interne Änderungen am Spiel selbst.
Die Bibliothek enthält einige Designoptionen mit Leistung, die hier kurz besprochen werden.
Wie Sokol GFX wird Sokol GP in der Zeichnungschleife niemals zu Allokation durchführen. Bei der Initialisierung müssen Sie daher die maximale Größe des Befehlswarteschlangenpuffers und den Eckpunktpuffer im Voraus konfigurieren.
Alle 2D -Raumtransformation (Funktionen wie sgp_rotate ) werden von der CPU und nicht von der GPU durchgeführt. Dies ist absichtlich, um zu vermeiden, dass zusätzlichen Overhead in der GPU hinzugefügt wird, da die Anzahl der Eckpunkte der 2D -Anwendungen normalerweise nicht so groß ist, und es ist effizienter, dass die Transformation die Transformation durch die Verschiebung der CPU unternimmt, um mehr zu pushen, als dass das GPU mit dem GPU mehr mit dem GPU über die GPU hinweg eingreift, als das GPU mit dem GPU zu den GPU zu pushen. CPU <--> GPU-Bus. Im Gegensatz dazu versandt 3D -Anwendungen normalerweise die Vertex -Transformationen mit einem Scheitelpunkt -Shader in die GPU.
Viele APIs, um den 2D -Raum vor dem Zeichnen eines Primitiven zu transformieren, sind verfügbar, z. B. Übersetzen, Drehen und Skalen. Sie können so ähnlich verwendet werden wie die in 3D -Grafik -APIs verfügbaren, aber sie werden nur für 2D gefertigt, beispielsweise bei der Verwendung von 2D müssen wir keine 4x4- oder 3x3 -Matrix verwenden, um die Vertex -Transformation durchzuführen. Stattdessen ist der Code für 2D spezialisiert und kann eine 2x3 -Matrix verwenden, wodurch zusätzliche CPU -Schwimmmeldungen verwendet werden.
Alle Pipelines verwenden immer eine damit verbundene Textur, selbst beim Zeichnen von nicht texturierten Primitiven, da sich die Grafikpipeline beim Mischen strukturierter Anrufe und nicht texturierten Anrufe ändert und die Effizienz verbessert.
Die Bibliothek ist im Stil der Sokol GFX -Headers codiert und viele Makros von dort sokol_gfx.h wiederverwendet.
Kopieren Sie sokol_gp.h zusammen mit anderen Sokol -Headern in denselben Ordner. Setzen Sie Sokol GFX wie gewöhnlich ein, fügen Sie dann sgp_setup(desc) direkt nach sg_setup(desc) auf und rufen Sie sie kurz vor sgp_shutdown() an sg_shutdown() . Beachten Sie, dass Sie normalerweise überprüfen sollten, ob SGP nach seiner Erstellung mit sgp_is_valid() gültig ist, und mit einem Fehler, wenn nicht, anmutig beenden.
Fügen Sie in Ihrer Rahmen -Zeichnungsfunktion sgp_begin(width, height) hinzu, bevor Sie eine SGP -Zeichnungsfunktion aufrufen, und zeichnen Sie Ihre Primitiven. Am Ende des Rahmens (oder FrameBuffer) sollten Sie immer sgp_flush() zwischen einem Sokol GFX -Start/End -Render -Durchgang aufrufen . sgp_flush() sendet alle Zeichnungsbefehle in Sokol GFX. Rufen Sie dann sgp_end() sofort an, um die Befehlswarteschlange Zeichnen zu verwerfen.
Ein aktuelles Beispiel für dieses Setup wird unten gezeigt.
Das Folgende ist ein kurzes Beispiel dafür, wie diese Bibliothek mit Sokol GFX und Sokol App in der Bibliothek in den Griff kommt:
// This is an example on how to set up and use Sokol GP to draw a filled rectangle.
// Includes Sokol GFX, Sokol GP and Sokol APP, doing all implementations.
#define SOKOL_IMPL
#include "sokol_gfx.h"
#include "sokol_gp.h"
#include "sokol_app.h"
#include "sokol_glue.h"
#include "sokol_log.h"
#include <stdio.h> // for fprintf()
#include <stdlib.h> // for exit()
#include <math.h> // for sinf() and cosf()
// Called on every frame of the application.
static void frame ( void ) {
// Get current window size.
int width = sapp_width (), height = sapp_height ();
float ratio = width /( float ) height ;
// Begin recording draw commands for a frame buffer of size (width, height).
sgp_begin ( width , height );
// Set frame buffer drawing region to (0,0,width,height).
sgp_viewport ( 0 , 0 , width , height );
// Set drawing coordinate space to (left=-ratio, right=ratio, top=1, bottom=-1).
sgp_project ( - ratio , ratio , 1.0f , -1.0f );
// Clear the frame buffer.
sgp_set_color ( 0.1f , 0.1f , 0.1f , 1.0f );
sgp_clear ();
// Draw an animated rectangle that rotates and changes its colors.
float time = sapp_frame_count () * sapp_frame_duration ();
float r = sinf ( time ) * 0.5 + 0.5 , g = cosf ( time ) * 0.5 + 0.5 ;
sgp_set_color ( r , g , 0.3f , 1.0f );
sgp_rotate_at ( time , 0.0f , 0.0f );
sgp_draw_filled_rect ( -0.5f , -0.5f , 1.0f , 1.0f );
// Begin a render pass.
sg_pass pass = {. swapchain = sglue_swapchain ()};
sg_begin_pass ( & pass );
// Dispatch all draw commands to Sokol GFX.
sgp_flush ();
// Finish a draw command queue, clearing it.
sgp_end ();
// End render pass.
sg_end_pass ();
// Commit Sokol render.
sg_commit ();
}
// Called when the application is initializing.
static void init ( void ) {
// Initialize Sokol GFX.
sg_desc sgdesc = {
. environment = sglue_environment (),
. logger . func = slog_func
};
sg_setup ( & sgdesc );
if (! sg_isvalid ()) {
fprintf ( stderr , "Failed to create Sokol GFX context!n" );
exit ( -1 );
}
// Initialize Sokol GP, adjust the size of command buffers for your own use.
sgp_desc sgpdesc = { 0 };
sgp_setup ( & sgpdesc );
if (! sgp_is_valid ()) {
fprintf ( stderr , "Failed to create Sokol GP context: %sn" , sgp_get_error_message ( sgp_get_last_error ()));
exit ( -1 );
}
}
// Called when the application is shutting down.
static void cleanup ( void ) {
// Cleanup Sokol GP and Sokol GFX resources.
sgp_shutdown ();
sg_shutdown ();
}
// Implement application main through Sokol APP.
sapp_desc sokol_main ( int argc , char * argv []) {
( void ) argc ;
( void ) argv ;
return ( sapp_desc ){
. init_cb = init ,
. frame_cb = frame ,
. cleanup_cb = cleanup ,
. window_title = "Rectangle (Sokol GP)" ,
. logger . func = slog_func ,
};
} Um dieses Beispiel auszuführen, kopieren Sie zuerst den Header sokol_gp.h zusammen mit anderen Sokol -Headern in denselben Ordner und kompilieren Sie dann mit jedem C -Compiler mit den richtigen Verknüpfungsflags (lesen Sie sokol_gfx.h ).
In Ordner samples finden Sie die folgenden vollständigen Beispiele, die alle APIs der Bibliothek abdecken:
sgp_begin() mit Frame-Puffern verwendet werden. Diese Beispiele werden als Testsuite für die Bibliothek verwendet. Sie können sie durch make erstellen.
Es ist möglich, dass nach vielen Zeichnen des Befehls oder des Vertex -Puffers überlaufen wird. In diesem Fall setzt die Bibliothek einen Fehlerfehlerstatus und funktioniert weiterhin normal. Wenn die Zeichnungsbefehlsbefehlswarteschlange mit sgp_flush() jedoch kein Befehl zeichnet, wird kein Zeichnungsbefehl entsandt. Dies kann geschehen, weil die Bibliothek vorgegebene Puffer verwendet. In solchen Fällen kann das Problem behoben werden, indem der vorangestellte Befehlswarteschlangenpuffer und der Scheitelpunktpuffer beim Aufrufen sgp_setup() erhöht werden.
Wenn Sie eine ungültige Anzahl von Push/Pops von sgp_push_transform() und sgp_pop_transform() oder zu vielen sgp_begin() und sgp_end() führen, kann dies auch zu Fehlern führen. Dies ist ein Nutzungsfehler.
Sie können das SOKOL_DEBUG -Makro in solchen Fällen aktivieren, um den Fehler programmgesteuert zu verarbeiten, indem Sie sgp_get_last_error() nach dem Aufrufen sgp_end() lesen. Es wird auch empfohlen, bei der Entwicklung SOKOL_DEBUG aktiviert zu lassen, wenn Sie sich mit Sokol entwickeln, damit Sie frühzeitig Fehler aufnehmen können.
Die Bibliothek unterstützt die üblichsten Mischmodi, die in 2D verwendet werden, nämlich:
SGP_BLENDMODE_NONE - No Mischung ( dstRGBA = srcRGBA ).SGP_BLENDMODE_BLEND -ALPHA-Mischung ( dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA)) und dstA = srcA + (dstA * (1-srcA)) )SGP_BLENDMODE_BLEND_PREMULTIPLIED -Pre-Multiplied Alpha-Mischung ( dstRGBA = srcRGBA + (dstRGBA * (1-srcA)) )SGP_BLENDMODE_ADD - additive Mischung ( dstRGB = (srcRGB * srcA) + dstRGB und dstA = dstA )SGP_BLENDMODE_ADD_PREMULTIPLIED - Pre -Multiplied Additive Mischung ( dstRGB = srcRGB + dstRGB und dstA = dstA )SGP_BLENDMODE_MOD - Farbmodulation ( dstRGB = srcRGB * dstRGB und dstA = dstA )SGP_BLENDMODE_MUL -Farbmultiply ( dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA)) und dstA = (srcA * dstA) + (dstA * (1-srcA)) ) Sie können den Bildschirmbereich so ändern, dass sie zeichnen, indem Sie sgp_viewport(x, y, width, height) aufrufen. Sie können das Koordinatensystem des 2D -Raums ändern, indem Sie sgp_project(left, right, top, bottom) aufrufen.
Sie können den 2D -Speicherplatz vor einem Ziehaufruf übersetzen, drehen oder skalieren, indem sgp_translate(x, y) die Transformationsfunktionen verwenden, die die Bibliothek bietet, z sgp_rotate(theta)
Um den Transformationsstatus zu speichern und wiederherzustellen, sollten Sie sgp_push_transform() und später sgp_pop_transform() aufrufen.
Die Bibliothek bietet Zeichnungsfunktionen für alle grundlegenden Primitiven, dh für Punkte, Linien, Dreiecke und Rechtecke wie sgp_draw_line() und sgp_draw_filled_rect() . Überprüfen Sie das Cheat -Blatt oder den Header, um weitere zu erhalten. Alle von ihnen haben Variationen angegriffen.
Um strukturierte Rechtecke zu zeichnen, können Sie sgp_set_image(0, img) und dann sgp_draw_filled_rect() verwenden, dadurch zeichnet dies eine gesamte Textur in ein Rechteck. Sie sollten das Bild später mit sgp_reset_image(0) zurücksetzen, um das gebundene Bild in das Standard -weißes Bild wiederherzustellen. Andernfalls haben Sie Störungen beim Zeichnen einer festen Farbe.
Falls Sie eine bestimmte Quelle aus der Textur ziehen möchten, sollten Sie stattdessen sgp_draw_textured_rect() verwenden.
Standardmäßig werden Texturen mit einem einfachen nächsten Filter -Sampler gezeichnet. Sie können den Sampler mit sgp_set_sampler(0, smp) ändern, bevor Sie eine Textur zeichnen. Es wird empfohlen, den Standard -Sampler mit sgp_reset_sampler(0) wiederherzustellen.
Alle üblichen Pipelines haben eine Farbmodulation, und Sie können eine Farbe vor einem Zeichnen modulieren, indem Sie die aktuelle Zustandsfarbe mit sgp_set_color(r,g,b,a) festlegen. Später sollten Sie die Farbe auf Standard (weiß) mit sgp_reset_color() zurücksetzen.
Wenn Sie einen benutzerdefinierten Shader verwenden, müssen Sie eine Pipeline mit sgp_make_pipeline(desc) mit Shader, Mischmodus und damit zugeordneten Zeichnenprimitive erstellen. Dann sollten Sie sgp_set_pipeline() aufrufen, bevor der Shader -Zeichnungsanruf. Sie sind dafür verantwortlich, denselben Mischmodus zu verwenden und primitiv wie die erstellte Pipeline zu zeichnen.
Benutzerdefinierte Uniformen können mit sgp_set_uniform(vs_data, vs_size, fs_data, fs_size) an den Shader übergeben werden, wo Sie immer einen Zeiger an eine Struktur mit genau demselben Schema und der gleichen Größe wie der im Scheitelpunkt und Fragment -Schatten definierte Schema übergeben sollten.
Obwohl Sie für jedes Grafik -Backend manuell benutzerdefinierte Shader erstellen können, sollte dies empfohlen werden, den Sokol Shader Compiler SHDC zu verwenden, da es Shader für mehrere Backends aus einer einzigen .glsl -Datei generieren kann, und dies funktioniert normalerweise gut.
Standardmäßig verfügt der Aufruf der Bibliotheksuniformpuffer pro Zeichnung nur 8 Float -Uniformen ( SGP_UNIFORM_CONTENT_SLOTS -Konfiguration), und das kann zu niedrig sein, um mit benutzerdefinierten Shadern zu verwenden. Dies ist die Standardeinstellung, da in der Regel Neuankömmlinge möglicherweise keine benutzerdefinierten 2D -Shader verwenden möchten, und das Erhöhen eines größeren Werts bedeutet mehr Overhead. Wenn Sie benutzerdefinierte Shader verwenden, erhöhen Sie bitte diesen Wert so groß genug, um die Anzahl der Uniformen Ihres größten Shaders zu halten.
Die folgenden Makros können definiert werden, bevor das Bibliotheksverhalten einbezogen wird:
SGP_BATCH_OPTIMIZER_DEPTH - Anzahl der Zeichnungsbefehle, auf die der Batch -Optimierer zurückblickt. Standard ist 8.SGP_UNIFORM_CONTENT_SLOTS - Maximale Anzahl von Schwimmern, die in jedem Ziehaufruf -Uniformpuffer gespeichert werden können. Standard ist 8.SGP_TEXTURE_SLOTS - Maximale Anzahl von Texturen, die pro Zeichnenanruf gebunden werden können. Standard ist 4. MIT, siehe Lizenzdatei oder Ende der Datei sokol_gp.h .
Hier finden Sie eine kurze Liste aller Bibliotheksfunktionen für schnelle Referenzen:
/* Initialization and de-initialization. */
void sgp_setup ( const sgp_desc * desc ); /* Initializes the SGP context, and should be called after `sg_setup`. */
void sgp_shutdown ( void ); /* Destroys the SGP context. */
bool sgp_is_valid ( void ); /* Checks if SGP context is valid, should be checked after `sgp_setup`. */
/* Error handling. */
sgp_error sgp_get_last_error ( void ); /* Returns last SGP error. */
const char * sgp_get_error_message ( sgp_error error ); /* Returns a message with SGP error description. */
/* Custom pipeline creation. */
sg_pipeline sgp_make_pipeline ( const sgp_pipeline_desc * desc ); /* Creates a custom shader pipeline to be used with SGP. */
/* Draw command queue management. */
void sgp_begin ( int width , int height ); /* Begins a new SGP draw command queue. */
void sgp_flush ( void ); /* Dispatch current Sokol GFX draw commands. */
void sgp_end ( void ); /* End current draw command queue, discarding it. */
/* 2D coordinate space projection */
void sgp_project ( float left , float right , float top , float bottom ); /* Set the coordinate space boundary in the current viewport. */
void sgp_reset_project ( void ); /* Resets the coordinate space to default (coordinate of the viewport). */
/* 2D coordinate space transformation. */
void sgp_push_transform ( void ); /* Saves current transform matrix, to be restored later with a pop. */
void sgp_pop_transform ( void ); /* Restore transform matrix to the same value of the last push. */
void sgp_reset_transform ( void ); /* Resets the transform matrix to identity (no transform). */
void sgp_translate ( float x , float y ); /* Translates the 2D coordinate space. */
void sgp_rotate ( float theta ); /* Rotates the 2D coordinate space around the origin. */
void sgp_rotate_at ( float theta , float x , float y ); /* Rotates the 2D coordinate space around a point. */
void sgp_scale ( float sx , float sy ); /* Scales the 2D coordinate space around the origin. */
void sgp_scale_at ( float sx , float sy , float x , float y ); /* Scales the 2D coordinate space around a point. */
/* State change for custom pipelines. */
void sgp_set_pipeline ( sg_pipeline pipeline ); /* Sets current draw pipeline. */
void sgp_reset_pipeline ( void ); /* Resets to the current draw pipeline to default (builtin pipelines). */
void sgp_set_uniform ( const void * vs_data , uint32_t vs_size , const void * fs_data , uint32_t fs_size ); /* Sets uniform buffer for a custom pipeline. */
void sgp_reset_uniform ( void ); /* Resets uniform buffer to default (current state color). */
/* State change functions for the common pipelines. */
void sgp_set_blend_mode ( sgp_blend_mode blend_mode ); /* Sets current blend mode. */
void sgp_reset_blend_mode ( void ); /* Resets current blend mode to default (no blending). */
void sgp_set_color ( float r , float g , float b , float a ); /* Sets current color modulation. */
void sgp_reset_color ( void ); /* Resets current color modulation to default (white). */
void sgp_set_image ( int channel , sg_image image ); /* Sets current bound image in a texture channel. */
void sgp_unset_image ( int channel ); /* Remove current bound image in a texture channel (no texture). */
void sgp_reset_image ( int channel ); /* Resets current bound image in a texture channel to default (white texture). */
void sgp_set_sampler ( int channel , sg_sampler sampler ); /* Sets current bound sampler in a texture channel. */
void sgp_unset_sampler ( int channel ); /* Remove current bound sampler in a texture channel (no sampler). */
void sgp_reset_sampler ( int channel ); /* Resets current bound sampler in a texture channel to default (nearest sampler). */
/* State change functions for all pipelines. */
void sgp_viewport ( int x , int y , int w , int h ); /* Sets the screen area to draw into. */
void sgp_reset_viewport ( void ); /* Reset viewport to default values (0, 0, width, height). */
void sgp_scissor ( int x , int y , int w , int h ); /* Set clip rectangle in the viewport. */
void sgp_reset_scissor ( void ); /* Resets clip rectangle to default (viewport bounds). */
void sgp_reset_state ( void ); /* Reset all state to default values. */
/* Drawing functions. */
void sgp_clear ( void ); /* Clears the current viewport using the current state color. */
void sgp_draw ( sg_primitive_type primitive_type , const sgp_vertex * vertices , uint32_t count ); /* Low level drawing function, capable of drawing any primitive. */
void sgp_draw_points ( const sgp_point * points , uint32_t count ); /* Draws points in a batch. */
void sgp_draw_point ( float x , float y ); /* Draws a single point. */
void sgp_draw_lines ( const sgp_line * lines , uint32_t count ); /* Draws lines in a batch. */
void sgp_draw_line ( float ax , float ay , float bx , float by ); /* Draws a single line. */
void sgp_draw_lines_strip ( const sgp_point * points , uint32_t count ); /* Draws a strip of lines. */
void sgp_draw_filled_triangles ( const sgp_triangle * triangles , uint32_t count ); /* Draws triangles in a batch. */
void sgp_draw_filled_triangle ( float ax , float ay , float bx , float by , float cx , float cy ); /* Draws a single triangle. */
void sgp_draw_filled_triangles_strip ( const sgp_point * points , uint32_t count ); /* Draws strip of triangles. */
void sgp_draw_filled_rects ( const sgp_rect * rects , uint32_t count ); /* Draws a batch of rectangles. */
void sgp_draw_filled_rect ( float x , float y , float w , float h ); /* Draws a single rectangle. */
void sgp_draw_textured_rects ( int channel , const sgp_textured_rect * rects , uint32_t count ); /* Draws a batch textured rectangle, each from a source region. */
void sgp_draw_textured_rect ( int channel , sgp_rect dest_rect , sgp_rect src_rect ); /* Draws a single textured rectangle from a source region. */
/* Querying functions. */
sgp_state * sgp_query_state ( void ); /* Returns the current draw state. */
sgp_desc sgp_query_desc ( void ); /* Returns description of the current SGP context. */ Diese Bibliothek wurde seit 2020 in privaten Projekten getestet und hat sich als stabil erwiesen.
Diese Bibliothek wurde ursprünglich von der MMORPG Game Medivia online gesponsert. Ich möchte ihnen für die Unterstützung meiner Arbeit danken.
Vielen Dank an @kkukshtel für das Sponsoring -Batching -Zeichnung mit verschiedenen Farben.
Stellen Sie sicher, dass Sie das exzellente Sokol -Projekt von @Floooh überprüfen, es bietet viele nützliche Einzelhochzeilen -C -Bibliotheken, die mit Qualität hergestellt werden, die für die Spieleentwicklung verwendet werden können.
Möglicherweise möchten Sie auch meinen anderen Einzelkopf -C -Bibliotheksminicoro überprüfen. Sie bringt stapelful Coroutinen für C, sehr nützlich, um endliche Staatsmaschinen in der Game Devmentment zu vereinfachen.
sgp_set_uniform -API ergibt, wurden neue vor-multiplimierte Mischmodi hinzugefügt. Hier sind einige Screenshots aller Proben im samples . Klicken Sie auf eines der Bilder, um es in Echtzeit in Ihrem Browser anzuzeigen.
Primitive Probe:
Mischmodi Muster:
Rahmenpufferprobe:
Rechteckprobe:
Effektprobe:
SDF -Probe:
Ich bin ein Vollzeit-Open-Source-Entwickler. Jede Menge der Spende durch meinen GitHub wird geschätzt und könnte mich ermutigen, diese und andere Open-Source-Projekte weiter zu unterstützen. Ich kann einmalige Sponsoring für kleine Funktionen oder geringfügige Verbesserungen akzeptieren, die mit den Projektzielen übereinstimmen, in diesem Fall kontaktieren Sie mich.